diff --git a/.gitignore b/.gitignore index f5c99bc..b3fd50b 100644 --- a/.gitignore +++ b/.gitignore @@ -68,3 +68,7 @@ TestResult.xml !packages.config .idea **/launchSettings.json + +.terraform/ +terraform.tfstate* +.terraform* \ No newline at end of file diff --git a/.nuke/build.schema.json b/.nuke/build.schema.json index dee87a0..7ee2355 100644 --- a/.nuke/build.schema.json +++ b/.nuke/build.schema.json @@ -85,6 +85,8 @@ "Compile", "CopyToLocalPackages", "Default", + "Integration", + "Integration2", "Pack", "Restore", "Test" @@ -105,6 +107,8 @@ "Compile", "CopyToLocalPackages", "Default", + "Integration", + "Integration2", "Pack", "Restore", "Test" diff --git a/build/Build.cs b/build/Build.cs index 9bd27a8..fee82fe 100644 --- a/build/Build.cs +++ b/build/Build.cs @@ -1,7 +1,14 @@ +using System; +using System.Linq; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; using Nuke.Common; +using Nuke.Common.CI.TeamCity; using Nuke.Common.Execution; using Nuke.Common.IO; using Nuke.Common.ProjectModel; +using Nuke.Common.Tooling; +using Nuke.Common.Tools.Docker; using Nuke.Common.Tools.DotNet; using Nuke.Common.Tools.OctoVersion; using Nuke.Common.Utilities.Collections; @@ -122,6 +129,116 @@ class Build : NukeBuild }); }); + + Target Integration2 => _ => _ + .Executes(() => + { + var composeDirectory = SourceDirectory / "Ldap.Integration.Tests/scripts/OpenLdap/"; + Environment.SetEnvironmentVariable("OCTOPUS_LDAP_OPENLDAP_PORT", "3777"); + + using (var process = ProcessTasks.StartProcess("pwsh", "./New-OpenLdapIntegrationTestEnvironment.ps1", composeDirectory)) + { + process.AssertZeroExitCode(); + } + + try + { + DotNetTest(_ => _ + .SetProjectFile(Solution) + .SetConfiguration(Configuration) + .SetFilter("AuthProvider=OpenLDAP") + .SetProcessArgumentConfigurator(arguments => arguments + .Add("--logger trx") + .Add("--logger console;verbosity=normal") + .Add(TeamCity.Instance is not null ? "--logger teamcity" : string.Empty) + )); + } + finally + { + using var process = ProcessTasks.StartProcess("pwsh", "./Remove-OpenLdapIntegrationTestEnvironment.ps1", composeDirectory); + process.AssertZeroExitCode(); + } + + + /*DockerTasks.Docker($"compose -f docker-compose.yml --project-name {CONTAINER_PROJECT} up -d", + composeDirectory); + + DotNetTest(_ => _ + .SetProjectFile(Solution) + .SetConfiguration(Configuration) + .SetFilter("AuthProvider=OpenLDAP") + .SetNoBuild(true) + .EnableNoRestore()); + + var x = ProcessTasks.StartShell("New-OpenLdapIntegrationTestEnvironment.ps1", composeDirectory); + x.WaitForExit(); + + DockerTasks.Docker($"compose -f docker-compose.yml --project-name {CONTAINER_PROJECT} down", + composeDirectory);*/ + }); + + Target Integration => _ => _ + .Executes(() => + { + var composeDirectory = SourceDirectory / "Ldap.Integration.Tests/scripts/ActiveDirectory/Azure/"; + + string public_ip_addr, admin_password; + + + using (var process = ProcessTasks.StartProcess("pwsh", "./New-ActiveDirectoryIntegrationTestEnvironment.ps1", composeDirectory)) + { + process.AssertZeroExitCode(); + } + + using (var process = ProcessTasks.StartProcess("terraform", "output -json", composeDirectory)) + { + process.AssertZeroExitCode(); + var rawJson = process.Output.Where(d => d.Type == OutputType.Std) + .Select(d => d.Text) + .Aggregate(string.Empty, (a, b) => $"{a}{Environment.NewLine}{b}"); + var raw = JsonConvert.DeserializeObject(rawJson); + + public_ip_addr = raw["public_ip_addr"].Value("value"); + admin_password = raw["admin_password"].Value("value"); + } + + try + { + DotNetTest(_ => _ + .SetProjectFile(Solution) + .SetConfiguration(Configuration) + .SetFilter("AuthProvider=ActiveDirectory") + .SetProcessEnvironmentVariable("OCTOPUS_LDAP_AD_SERVER", public_ip_addr) + .SetProcessEnvironmentVariable("OCTOPUS_LDAP_AD_PASSWORD", admin_password) + .SetProcessArgumentConfigurator(arguments => arguments + .Add("--logger trx") + .Add("--logger console;verbosity=normal") + )); + } + finally + { + using var process = ProcessTasks.StartProcess("pwsh", "./Remove-ActiveDirectoryIntegrationTestEnvironment.ps1", composeDirectory); + process.AssertZeroExitCode(); + } + + + /*DockerTasks.Docker($"compose -f docker-compose.yml --project-name {CONTAINER_PROJECT} up -d", + composeDirectory); + + DotNetTest(_ => _ + .SetProjectFile(Solution) + .SetConfiguration(Configuration) + .SetFilter("AuthProvider=OpenLDAP") + .SetNoBuild(true) + .EnableNoRestore()); + + var x = ProcessTasks.StartShell("New-OpenLdapIntegrationTestEnvironment.ps1", composeDirectory); + x.WaitForExit(); + + DockerTasks.Docker($"compose -f docker-compose.yml --project-name {CONTAINER_PROJECT} down", + composeDirectory);*/ + }); + Target Default => _ => _ .DependsOn(Pack); diff --git a/global.json b/global.json new file mode 100644 index 0000000..2675d76 --- /dev/null +++ b/global.json @@ -0,0 +1,7 @@ +{ + "sdk": { + "version": "5.0.100", + "rollForward": "latestFeature", + "allowPrerelease": false + } +} \ No newline at end of file diff --git a/source/Ldap.Integration.Tests/ICanMatchExternalUserTests.cs b/source/Ldap.Integration.Tests/ICanMatchExternalUserTests.cs index 8d0d389..dde46ef 100644 --- a/source/Ldap.Integration.Tests/ICanMatchExternalUserTests.cs +++ b/source/Ldap.Integration.Tests/ICanMatchExternalUserTests.cs @@ -17,6 +17,7 @@ public TheMatchMethod(ITestOutputHelper testLogger) } [Fact] + [Trait("AuthProvider","ActiveDirectory")] internal void MatchesAUserFromActiveDirectory() { var userName = "developer1"; @@ -37,6 +38,7 @@ internal void MatchesAUserFromActiveDirectory() } [Fact] + [Trait("AuthProvider","OpenLDAP")] internal void MatchesAUserFromOpenLDAP() { var userName = "developer1"; diff --git a/source/Ldap.Integration.Tests/ICanSearchExternalGroupsTests.cs b/source/Ldap.Integration.Tests/ICanSearchExternalGroupsTests.cs index 0d963ee..1efe048 100644 --- a/source/Ldap.Integration.Tests/ICanSearchExternalGroupsTests.cs +++ b/source/Ldap.Integration.Tests/ICanSearchExternalGroupsTests.cs @@ -19,6 +19,7 @@ public TheSearchMethod(ITestOutputHelper testLogger) } [Fact] + [Trait("AuthProvider","ActiveDirectory")] internal void FindsGroupsFromActiveDirectory() { var partialName = "Devel"; @@ -56,6 +57,7 @@ internal void FindsGroupsFromActiveDirectoryWithSpecialCharacters() } [Fact] + [Trait("AuthProvider","OpenLDAP")] internal void FindsGroupsFromOpenLDAP() { var partialName = "Devel"; @@ -74,6 +76,7 @@ internal void FindsGroupsFromOpenLDAP() } [Fact] + [Trait("AuthProvider","OpenLDAP")] internal void FindsGroupsFromOpenLDAPWithSpecialCharacters() { var partialName = "Special"; diff --git a/source/Ldap.Integration.Tests/ICanSearchExternalUsersTests.cs b/source/Ldap.Integration.Tests/ICanSearchExternalUsersTests.cs index 0f4d286..54d43a1 100644 --- a/source/Ldap.Integration.Tests/ICanSearchExternalUsersTests.cs +++ b/source/Ldap.Integration.Tests/ICanSearchExternalUsersTests.cs @@ -18,6 +18,7 @@ public TheSearchMethod(ITestOutputHelper testLogger) } [Fact] + [Trait("AuthProvider","ActiveDirectory")] internal void FindsUsersFromActiveDirectory() { var partialName = "devel"; @@ -35,6 +36,7 @@ internal void FindsUsersFromActiveDirectory() } [Fact] + [Trait("AuthProvider","OpenLDAP")] internal void FindsUsersFromOpenLDAP() { var partialName = "devel"; diff --git a/source/Ldap.Integration.Tests/IDoesBasicAuthenticationTests.cs b/source/Ldap.Integration.Tests/IDoesBasicAuthenticationTests.cs index 4a1d3b7..5b5507c 100644 --- a/source/Ldap.Integration.Tests/IDoesBasicAuthenticationTests.cs +++ b/source/Ldap.Integration.Tests/IDoesBasicAuthenticationTests.cs @@ -20,6 +20,7 @@ public TheValidateCredentialsMethod(ITestOutputHelper testLogger) } [Fact] + [Trait("AuthProvider","ActiveDirectory")] internal void ValidatesAUserFromActiveDirectory() { // Arrange @@ -45,6 +46,7 @@ internal void ValidatesAUserFromActiveDirectory() } [Fact] + [Trait("AuthProvider","OpenLDAP")] internal void ValidatesAUserFromOpenLDAP() { // Arrange diff --git a/source/Ldap.Integration.Tests/IExternalGroupRetrieverTests.cs b/source/Ldap.Integration.Tests/IExternalGroupRetrieverTests.cs index 9026056..166a0d2 100644 --- a/source/Ldap.Integration.Tests/IExternalGroupRetrieverTests.cs +++ b/source/Ldap.Integration.Tests/IExternalGroupRetrieverTests.cs @@ -19,6 +19,7 @@ public TheReadMethod(ITestOutputHelper testLogger) } [Fact] + [Trait("AuthProvider","ActiveDirectory")] internal void ReadsGroupsForAUserFromActiveDirectory() { // Arrange @@ -48,6 +49,7 @@ internal void ReadsGroupsForAUserFromActiveDirectory() } [Fact] + [Trait("AuthProvider","ActiveDirectory")] internal void ReadsGroupsForAUserFromActiveDirectoryWithSpecialCharacters() { // Arrange @@ -77,6 +79,7 @@ internal void ReadsGroupsForAUserFromActiveDirectoryWithSpecialCharacters() } [Fact] + [Trait("AuthProvider","OpenLDAP")] internal void ReadsGroupsForAUserFromOpenLDAP() { // Arrange @@ -107,6 +110,7 @@ internal void ReadsGroupsForAUserFromOpenLDAP() } [Fact] + [Trait("AuthProvider","OpenLDAP")] internal void ReadsGroupsForAUserFromOpenLDAPWithSpecialCharacters() { // Arrange diff --git a/source/Ldap.Integration.Tests/ISupportsAutoUserCreationFromPrincipalTests.cs b/source/Ldap.Integration.Tests/ISupportsAutoUserCreationFromPrincipalTests.cs index 586ec49..66aeaba 100644 --- a/source/Ldap.Integration.Tests/ISupportsAutoUserCreationFromPrincipalTests.cs +++ b/source/Ldap.Integration.Tests/ISupportsAutoUserCreationFromPrincipalTests.cs @@ -20,6 +20,7 @@ public TheGetOrCreateUserMethod(ITestOutputHelper testLogger) } [Fact] + [Trait("AuthProvider","ActiveDirectory")] internal void CreatesAUserFromActiveDirectory() { // Arrange @@ -44,6 +45,7 @@ internal void CreatesAUserFromActiveDirectory() } [Fact] + [Trait("AuthProvider","OpenLDAP")] internal void CreatesAUserFromOpenLDAP() { // Arrange diff --git a/source/Ldap.Integration.Tests/Ldap.Integration.Tests.csproj b/source/Ldap.Integration.Tests/Ldap.Integration.Tests.csproj index 1aeff8f..d3dfff4 100644 --- a/source/Ldap.Integration.Tests/Ldap.Integration.Tests.csproj +++ b/source/Ldap.Integration.Tests/Ldap.Integration.Tests.csproj @@ -9,6 +9,7 @@ + runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/source/Ldap.Integration.Tests/README.md b/source/Ldap.Integration.Tests/README.md index a0cc7a2..8acf3c8 100644 --- a/source/Ldap.Integration.Tests/README.md +++ b/source/Ldap.Integration.Tests/README.md @@ -10,12 +10,12 @@ A docker-compose stack is defined that spins up an openldap server bootstrapped Environment variables can be used to configure the integration test settings. -| Env Var | Required | Default Value | -| --- | --- | --- | -| `OCTOPUS_LDAP_OPENLDAP_SERVER` | No | localhost | -| `OCTOPUS_LDAP_OPENLDAP_PORT` | No | 389 | +| Env Var | Required | Default Value | +| --- | --- |------------------------------| +| `OCTOPUS_LDAP_OPENLDAP_SERVER` | No | localhost | +| `OCTOPUS_LDAP_OPENLDAP_PORT` | No | 389 | | `OCTOPUS_LDAP_OPENLDAP_USER` | No | cn=admin,dc=domain1,dc=local | -| `OCTOPUS_LDAP_OPENLDAP_PASSWORD` | Yes | | +| `OCTOPUS_LDAP_OPENLDAP_PASSWORD` | Yes | Pass | ### Running Integration Tests @@ -34,34 +34,29 @@ Powershell scripts are located [here](scripts/OpenLdap) to create/tear down the ``` ## Active Directory - As it is not possible to containerize Microsoft AD, these need to be run against a VM hosted instance somewhere that gets populated with known test data. -[This Azure Template](https://github.com/maxskunkworks/TLG/tree/master/tlg-base-config_3-vm) is one relatively straight forward option to create an AD environment. Firewall settings will generally need to applied manually to enable inbound connections. - ### Configuration Environment variables can be used to configure the integration test settings. -| Env Var | Required | Default Value | -| --- | --- | --- | -| `OCTOPUS_LDAP_AD_SERVER` | Yes | | -| `OCTOPUS_LDAP_AD_PORT` | No | 389 | -| `OCTOPUS_LDAP_AD_USER` | Yes | | +| Env Var | Required | Default Value | +| --- | --- |---------------------------| +| `OCTOPUS_LDAP_AD_SERVER` | Yes | | +| `OCTOPUS_LDAP_AD_PORT` | No | 389 | +| `OCTOPUS_LDAP_AD_USER` | Yes | adminuser@mycompany.local | | `OCTOPUS_LDAP_AD_PASSWORD` | Yes | | ### Running Integration Tests +A terraform script has been provided [here](scripts/ActiveDirectory/Azure) that will provision an AD instance in Azure along with relevant test data. -Powershell scripts are located [here](scripts/ActiveDirectory) to populate an existing ActiveDirectory instance with the required test data. Due to cross platform and other limmitations, they currently are simple scripts that must be run from a machine connected to the test domain using an account with appropriate permissions. - -- Populate the integration test data +- Create the integration test stack ``` -./Update-ActiveDirectoryIntegrationTestData.ps1 +./New-ActiveDirectoryIntegrationTestEnvironment.ps1 ``` - -- Run the ActiveDirectory integration tests - -- Cleanup the integration test data +- Update your environment variables with the generated server IP and password. +- Run the OpenLdap integration tests +- Tear down the integration test stack +``` +./Remove-ActiveDirectoryIntegrationTestEnvironment.ps1 ``` -./Remove-ActiveDirectoryIntegrationTestData.ps1 -``` \ No newline at end of file diff --git a/source/Ldap.Integration.Tests/TestHelpers/ConfigurationHelper.cs b/source/Ldap.Integration.Tests/TestHelpers/ConfigurationHelper.cs index 04e094e..2fc6057 100644 --- a/source/Ldap.Integration.Tests/TestHelpers/ConfigurationHelper.cs +++ b/source/Ldap.Integration.Tests/TestHelpers/ConfigurationHelper.cs @@ -17,10 +17,10 @@ internal static class ConfigurationHelper public static LdapConfiguration GetActiveDirectoryConfiguration() { - var server = Environment.GetEnvironmentVariable(ENVVAR_AD_SERVER); + var server = Environment.GetEnvironmentVariable(ENVVAR_AD_SERVER) ?? "20.231.14.150"; var port = Convert.ToInt32(Environment.GetEnvironmentVariable(ENVVAR_AD_PORT) ?? "389"); - var user = Environment.GetEnvironmentVariable(ENVVAR_AD_USER); - var password = Environment.GetEnvironmentVariable(ENVVAR_AD_PASSWORD); + var user = Environment.GetEnvironmentVariable(ENVVAR_AD_USER) ?? "adminuser@mycompany.local"; + var password = Environment.GetEnvironmentVariable(ENVVAR_AD_PASSWORD) ?? "Z@qDBHRXQmwoXBTs"; return new LdapConfiguration() .Enabled() @@ -51,7 +51,7 @@ public static LdapConfiguration GetOpenLdapConfiguration() var server = Environment.GetEnvironmentVariable(ENVVAR_OPENLDAP_SERVER) ?? "localhost"; var port = Convert.ToInt32(Environment.GetEnvironmentVariable(ENVVAR_OPENLDAP_PORT) ?? "389"); var user = Environment.GetEnvironmentVariable(ENVVAR_OPENLDAP_USER) ?? "cn=admin,dc=domain1,dc=local"; - var password = Environment.GetEnvironmentVariable(ENVVAR_OPENLDAP_PASSWORD); + var password = Environment.GetEnvironmentVariable(ENVVAR_OPENLDAP_PASSWORD) ?? "Pass"; return new LdapConfiguration() .Enabled() diff --git a/source/Ldap.Integration.Tests/scripts/ActiveDirectory/Azure/New-ActiveDirectoryIntegrationTestEnvironment.ps1 b/source/Ldap.Integration.Tests/scripts/ActiveDirectory/Azure/New-ActiveDirectoryIntegrationTestEnvironment.ps1 new file mode 100644 index 0000000..32c37a1 --- /dev/null +++ b/source/Ldap.Integration.Tests/scripts/ActiveDirectory/Azure/New-ActiveDirectoryIntegrationTestEnvironment.ps1 @@ -0,0 +1,16 @@ +Write-Output "Setting up Azure AD Terraform stack" + +terraform init +terraform plan +terraform apply --auto-approve + +#We ned to refresh the state since the public vm IP isn't allocated when the resource is first provisioned +terraform refresh + +$output=(terraform output -json | ConvertFrom-json) +Write-Host "Update your Environment Variables" +Write-Host " OCTOPUS_LDAP_AD_SERVER=$($output.public_ip_addr.value)" +Write-Host " OCTOPUS_LDAP_AD_USER=$($output.admin_username.value)@mycompany.local" +Write-Host " OCTOPUS_LDAP_AD_PASSWORD=$($output.admin_password.value)" +Write-Host " OCTOPUS_LDAP_AD_PORT=389" + diff --git a/source/Ldap.Integration.Tests/scripts/ActiveDirectory/Azure/Remove-ActiveDirectoryIntegrationTestEnvironment.ps1 b/source/Ldap.Integration.Tests/scripts/ActiveDirectory/Azure/Remove-ActiveDirectoryIntegrationTestEnvironment.ps1 new file mode 100644 index 0000000..bc20ae5 --- /dev/null +++ b/source/Ldap.Integration.Tests/scripts/ActiveDirectory/Azure/Remove-ActiveDirectoryIntegrationTestEnvironment.ps1 @@ -0,0 +1,6 @@ +Write-Output "Tearing down Azure AD Terraform stack" + +terraform destroy --auto-approve + +Write-Output "DONE!" +exit 0 \ No newline at end of file diff --git a/source/Ldap.Integration.Tests/scripts/ActiveDirectory/Update-ActiveDirectoryIntegrationTestData.ps1 b/source/Ldap.Integration.Tests/scripts/ActiveDirectory/Azure/Scripts/ConfigureActiveDirectoryData.ps1 similarity index 100% rename from source/Ldap.Integration.Tests/scripts/ActiveDirectory/Update-ActiveDirectoryIntegrationTestData.ps1 rename to source/Ldap.Integration.Tests/scripts/ActiveDirectory/Azure/Scripts/ConfigureActiveDirectoryData.ps1 diff --git a/source/Ldap.Integration.Tests/scripts/ActiveDirectory/Azure/Scripts/InstallActiveDirectoryServices.ps1 b/source/Ldap.Integration.Tests/scripts/ActiveDirectory/Azure/Scripts/InstallActiveDirectoryServices.ps1 new file mode 100644 index 0000000..ead4b81 --- /dev/null +++ b/source/Ldap.Integration.Tests/scripts/ActiveDirectory/Azure/Scripts/InstallActiveDirectoryServices.ps1 @@ -0,0 +1,19 @@ +Write-Host $(Get-Date) " >> Starting" + +Import-Module ServerManager +Install-windowsfeature -name AD-Domain-Services –IncludeManagementTools +Install-WindowsFeature –Name GPMC +Write-Host $(Get-Date) " >> Tools Installed" + + +$domainname = "mycompany.local" +$NTDPath = "C:\Windows\ntds" +$logPath = "C:\Windows\ntds" +$sysvolPath = "C:\Windows\Sysvol" +$domainmode = "win2012R2" +$forestmode = "win2012R2" +$password = ConvertTo-SecureString "AdminPassword01!!" -AsPlainText -Force +Install-ADDSForest -CreateDnsDelegation:$false -DatabasePath $NTDPath -SafeModeAdministratorPassword $password -DomainMode $domainmode -DomainName $domainname -ForestMode $forestmode -InstallDns:$true -LogPath $logPath -NoRebootOnCompletion:$true -SysvolPath $sysvolPath -Force:$true +Write-Host $(Get-Date) " >> AD Configured" + +shutdown /f /r /t 1 \ No newline at end of file diff --git a/source/Ldap.Integration.Tests/scripts/ActiveDirectory/Azure/main.tf b/source/Ldap.Integration.Tests/scripts/ActiveDirectory/Azure/main.tf new file mode 100644 index 0000000..b1b3e59 --- /dev/null +++ b/source/Ldap.Integration.Tests/scripts/ActiveDirectory/Azure/main.tf @@ -0,0 +1,169 @@ +terraform { + required_version = ">=0.12" + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = "~>2.0" + } + } +} + +provider "azurerm" { + features {} +} + +## +resource "azurerm_resource_group" "rg" { + name = "rg_authtest_ad" + location = var.resource_group_location +} + +## +resource "azurerm_virtual_network" "vnet" { + name = "vNet1" + address_space = ["10.0.0.0/16"] + location = azurerm_resource_group.rg.location + resource_group_name = azurerm_resource_group.rg.name +} + +## +resource "azurerm_subnet" "subnet" { + name = "subnet" + resource_group_name = azurerm_resource_group.rg.name + virtual_network_name = azurerm_virtual_network.vnet.name + address_prefixes = ["10.0.2.0/24"] +} + +resource "azurerm_public_ip" "public_ip" { + name = "public_ip" + resource_group_name = azurerm_resource_group.rg.name + location = azurerm_resource_group.rg.location + allocation_method = "Dynamic" +} + +## +resource "azurerm_network_interface" "example" { + name = "nic1" + location = azurerm_resource_group.rg.location + resource_group_name = azurerm_resource_group.rg.name + + + ip_configuration { + name = "internal" + subnet_id = azurerm_subnet.subnet.id + private_ip_address_allocation = "Dynamic" + public_ip_address_id = azurerm_public_ip.public_ip.id + } +} + +# Create Network Security Group and rule +resource "azurerm_network_security_group" "myterraformnsg" { + name = "securitygroup" + location = azurerm_resource_group.rg.location + resource_group_name = azurerm_resource_group.rg.name + + security_rule { + name = "LDAP" + priority = 1002 + direction = "Inbound" + access = "Allow" + protocol = "Tcp" + source_port_range = "*" + destination_port_range = "389" + source_address_prefix = "*" + destination_address_prefix = "*" + } +} + +resource "azurerm_network_interface_security_group_association" "example" { + network_interface_id = azurerm_network_interface.example.id + network_security_group_id = azurerm_network_security_group.myterraformnsg.id +} + + +resource "random_password" "password" { + length = 16 + special = true + override_special = "_%@" +} + +## +resource "azurerm_windows_virtual_machine" "example" { + name = "ad-vm" + resource_group_name = azurerm_resource_group.rg.name + location = azurerm_resource_group.rg.location + size = "Standard_F2" + admin_username = "adminuser" + admin_password = random_password.password.result + network_interface_ids = [ + azurerm_network_interface.example.id, + ] + + os_disk { + caching = "ReadWrite" + storage_account_type = "Standard_LRS" + } + + source_image_reference { + publisher = "MicrosoftWindowsServer" + offer = "WindowsServer" + sku = "2016-Datacenter" + version = "latest" + } +} + +#Provisioning the AD Services +resource "azurerm_virtual_machine_extension" "ad_install" { + name = "Active_Directory_Installation" + virtual_machine_id = azurerm_windows_virtual_machine.example.id + publisher = "Microsoft.Compute" + type = "CustomScriptExtension" + type_handler_version = "1.10" + + protected_settings = <