예제 #1
0
    public DevOpsInfra()
    {
        _config = new Config("ado");

        #pragma warning disable
        Pulumi.InputMap <string> tags = JsonConvert.DeserializeObject <Dictionary <string, string> >(_config.RequireObject <JsonElement>("tags").ToString());

        #region AzureNative.Resources.ResourceGroup (-rg)
        var resourceGroup = new Pulumi.AzureNative.Resources.ResourceGroup($"{_config.Require("resourceGroup")}-{_config.Require("env")}-rg-", new Pulumi.AzureNative.Resources.ResourceGroupArgs
        {
            Location = _config.Require("location"),
            Tags     = tags,
        });
        this.ResourceGroupName = resourceGroup.Name;
        #endregion

        #region NetworkSecurityGroup (-nsg)
        // NSGs can be connected to Subnets or Network cards (NICs).
        // When applied to the subnet, the NSG applies to all VMs on that subnet. If you apply only to the NIC card, just that one VM is affected.
        string myIp = new System.Net.WebClient().DownloadString("https://api.ipify.org");
        var    networkSecurityGroup = new Pulumi.AzureNative.Network.NetworkSecurityGroup($"{_config.Require("vnet.name")}-{_config.Require("env")}-nsg-", new Pulumi.AzureNative.Network.NetworkSecurityGroupArgs
        {
            ResourceGroupName = resourceGroup.Name,
            SecurityRules     =
            {
                new Pulumi.AzureNative.Network.Inputs.SecurityRuleArgs
                {
                    Name                     = "allow-rdp",
                    Protocol                 = SecurityRuleProtocol.Tcp,
                    SourcePortRange          = "*",
                    DestinationPortRange     = "3389",
                    SourceAddressPrefix      = myIp,
                    DestinationAddressPrefix = "*",
                    Access                   = "Allow",
                    Priority                 = 300,
                    Direction                = "Inbound",
                },

                new Pulumi.AzureNative.Network.Inputs.SecurityRuleArgs
                {
                    Name                     = "allow-http", // _config.Require("nsg.name"),
                    Protocol                 = SecurityRuleProtocol.Tcp,
                    SourcePortRange          = "*",
                    DestinationPortRange     = "443",
                    SourceAddressPrefix      = "*",
                    DestinationAddressPrefix = "*",
                    Access                   = "Allow",
                    Priority                 = 301,
                    Direction                = "Inbound",
                },
            },
        });
        #endregion

        #region VirtualNetwork (-vnet)
        var network = new VirtualNetwork($"{_config.Require("vnet.name")}-{_config.Require("env")}-vnet-",
                                         new VirtualNetworkArgs
        {
            AddressSpace = new Pulumi.AzureNative.Network.Inputs.AddressSpaceArgs
            {
                AddressPrefixes =
                {
                    _config.Require("vnet.cidr"),
                },
            },
            Location          = _config.Require("location"),
            ResourceGroupName = resourceGroup.Name,
            Subnets           =
            {
                new Pulumi.AzureNative.Network.Inputs.SubnetArgs
                {
                    AddressPrefix = _config.Require("bastion.cidr"),
                    Name          = "AzureBastionSubnet",
                },
                new Pulumi.AzureNative.Network.Inputs.SubnetArgs
                {
                    AddressPrefix        = _config.Require("snet.cidr"),
                    Name                 = _config.Require("snet.name"),
                    NetworkSecurityGroup = new Pulumi.AzureNative.Network.Inputs.NetworkSecurityGroupArgs
                    {
                        Id = networkSecurityGroup.Id,
                    },
                },
            },
            VirtualNetworkName = "AzureDevOps",
            // VirtualNetworkPeerings
            EnableDdosProtection = false,
        }
                                         );
        #endregion

        #region PublicIp (-ip)
        var publicIp = new Pulumi.AzureNative.Network.PublicIPAddress($"bastion-{_config.Require("env")}-ip-", new Pulumi.AzureNative.Network.PublicIPAddressArgs
        {
            PublicIPAddressVersion   = IPVersion.IPv4,
            PublicIPAllocationMethod = IPAllocationMethod.Static,
            IdleTimeoutInMinutes     = 4,
            Location          = _config.Require("location"),
            ResourceGroupName = resourceGroup.Name,
            Sku = new Pulumi.AzureNative.Network.Inputs.PublicIPAddressSkuArgs
            {
                Name = PublicIPAddressSkuName.Standard,
                Tier = PublicIPAddressSkuTier.Regional,
            },
        });
        var vmPublicIp = new Pulumi.AzureNative.Network.PublicIPAddress($"{_config.Require("agent.name")}-{_config.Require("env")}-ip-", new Pulumi.AzureNative.Network.PublicIPAddressArgs
        {
            PublicIPAddressVersion   = IPVersion.IPv4,
            PublicIPAllocationMethod = IPAllocationMethod.Static,
            IdleTimeoutInMinutes     = 4,
            Location          = _config.Require("location"),
            ResourceGroupName = resourceGroup.Name,
            Sku = new Pulumi.AzureNative.Network.Inputs.PublicIPAddressSkuArgs
            {
                Name = PublicIPAddressSkuName.Standard,
                Tier = PublicIPAddressSkuTier.Regional,
            },
        });

        #endregion

        #region NetworkInterface (-nic)
        var networkInterface = new Pulumi.AzureNative.Network.NetworkInterface($"{_config.Require("agent.name")}-{_config.Require("env")}-nic-", new Pulumi.AzureNative.Network.NetworkInterfaceArgs
        {
            // AdoAgent has size Standard_B2s, which is not compatible with  accelerated networking on network interface.
            // https://docs.microsoft.com/en-us/azure/virtual-network/create-vm-accelerated-networking-powershell
            // EnableAcceleratedNetworking = true,
            IpConfigurations =
            {
                new Pulumi.AzureNative.Network.Inputs.NetworkInterfaceIPConfigurationArgs
                {
                    Name    = "ipconfig1",
                    Primary = true,
                    PrivateIPAllocationMethod = IPAllocationMethod.Dynamic,
                    PrivateIPAddressVersion   = "IPv4",
                    PublicIPAddress           = new Pulumi.AzureNative.Network.Inputs.PublicIPAddressArgs
                    {
                        Id = vmPublicIp.Id,
                    },
                    Subnet = new Pulumi.AzureNative.Network.Inputs.SubnetArgs
                    {
                        #pragma warning disable
                        Id = network.Subnets.Apply(s => s[1].Id),
                    },
                },
            },
            Location          = _config.Require("location"),
            ResourceGroupName = resourceGroup.Name,
        });
        #endregion

        #region VirtualMachine (-vm)
        var vm = new Pulumi.AzureNative.Compute.VirtualMachine($"{_config.Require("agent.name")}-{_config.Require("env")}-vmi-", new Pulumi.AzureNative.Compute.VirtualMachineArgs
        {
            ResourceGroupName = resourceGroup.Name,
            HardwareProfile   = new Pulumi.AzureNative.Compute.Inputs.HardwareProfileArgs {
                VmSize = _config.Require("vm.vmSize")
            },
            VmName             = "AdoAgent",
            DiagnosticsProfile = new Pulumi.AzureNative.Compute.Inputs.DiagnosticsProfileArgs
            {
                BootDiagnostics = new Pulumi.AzureNative.Compute.Inputs.BootDiagnosticsArgs {
                    Enabled = true
                }
            },
            NetworkProfile = new Pulumi.AzureNative.Compute.Inputs.NetworkProfileArgs
            {
                NetworkInterfaces =
                {
                    new Pulumi.AzureNative.Compute.Inputs.NetworkInterfaceReferenceArgs
                    {
                        Id      = networkInterface.Id,
                        Primary = true,
                    },
                }
            },
            StorageProfile = new Pulumi.AzureNative.Compute.Inputs.StorageProfileArgs
            {
                ImageReference = new Pulumi.AzureNative.Compute.Inputs.ImageReferenceArgs
                {
                    Publisher = "MicrosoftWindowsServer",
                    Offer     = "WindowsServer",
                    Sku       = "2019-Datacenter-with-Containers-smalldisk",
                    Version   = "latest"
                },

                OsDisk = new Pulumi.AzureNative.Compute.Inputs.OSDiskArgs
                {
                    OsType       = Pulumi.AzureNative.Compute.OperatingSystemTypes.Windows,
                    Name         = "system",
                    CreateOption = Pulumi.AzureNative.Compute.DiskCreateOptionTypes.FromImage,
                    Caching      = Pulumi.AzureNative.Compute.CachingTypes.ReadWrite,
                    ManagedDisk  = new Pulumi.AzureNative.Compute.Inputs.ManagedDiskParametersArgs
                    {
                        StorageAccountType = Pulumi.AzureNative.Compute.StorageAccountTypes.Standard_LRS,
                    },
                    DiskSizeGB = 100,
                },

                DataDisks =
                {
                    new Pulumi.AzureNative.Compute.Inputs.DataDiskArgs
                    {
                        Name         = "Data",
                        CreateOption = Pulumi.AzureNative.Compute.DiskCreateOptionTypes.Empty,
                        DiskSizeGB   = _config.RequireInt32("vm.diskSizeGB"),
                        Lun          = 0,
                        Caching      = Pulumi.AzureNative.Compute.CachingTypes.None,
                    },
                },
            },
            OsProfile = new Pulumi.AzureNative.Compute.Inputs.OSProfileArgs
            {
                ComputerName         = _config.Require("agent.name"),
                AdminUsername        = _config.Require("admin.user"),
                AdminPassword        = _config.RequireSecret("admin.pw"),
                WindowsConfiguration = new Pulumi.AzureNative.Compute.Inputs.WindowsConfigurationArgs
                {
                    ProvisionVMAgent       = true,
                    EnableAutomaticUpdates = true,
                    PatchSettings          = new Pulumi.AzureNative.Compute.Inputs.PatchSettingsArgs
                    {
                        PatchMode         = Pulumi.AzureNative.Compute.WindowsVMGuestPatchMode.AutomaticByOS,
                        EnableHotpatching = false,
                    },
                },
            },
        });     // new CustomResourceOptions { DeleteBeforeReplace = true });
        #endregion

        #region BastionHost (-bas)
        // Azure Bastion is a fully managed PaaS service that provides secure and seamless RDP and SSH access to virtual machines through the Azure Portal.
        // A BastionHost is provisioned within a Virtual Network (VNet) to provid SSL access to all VMs in the VNet without exposure through public IP addresses.
        var bastionHost = new Pulumi.AzureNative.Network.BastionHost($"{_config.Require("vnet.name")}-{_config.Require("env")}-bas-", new Pulumi.AzureNative.Network.BastionHostArgs
        {
            Location          = resourceGroup.Location,
            ResourceGroupName = resourceGroup.Name,
            IpConfigurations  =
            {
                new Pulumi.AzureNative.Network.Inputs.BastionHostIPConfigurationArgs
                {
                    Name            = "bastionHostIpConfiguration",
                    PublicIPAddress = new Pulumi.AzureNative.Network.Inputs.SubResourceArgs
                    {
                        Id = publicIp.Id,
                    },
                    Subnet = new Pulumi.AzureNative.Network.Inputs.SubResourceArgs
                    {
                        Id = network.Subnets.Apply(s => s[0].Id),
                    },
                },
            },
        });
        #endregion
    }
예제 #2
0
    static Task <int> Main()
    {
        return(Deployment.RunAsync(async() => {
            // Get the configuration and required variables
            var config = new Pulumi.Config();
            var location = config.Require("location");
            var companyCode = config.Require("company_code");
            var environment = config.Require("environment");
            var scope = config.Require("default_scope");
            var tenantId = Output.Create <string>(config.Require("tenant_id"));
            var rbacGroups = config.RequireObject <JsonElement>("rbac_groups");
            List <string> rbacGroupsList = new List <string>();
            foreach (JsonElement group in rbacGroups.EnumerateArray())
            {
                rbacGroupsList.Add(group.ToString());
            }

            // Create the factory
            ResourceFactory factory = new ResourceFactory(companyCode, location, environment, scope);

            // Create the tags to be applied to these resources: scope
            Dictionary <string, string> tags = new Dictionary <string, string>();
            tags.Add("scope", scope);

            // Create the resource group, analytics workspace and automation account
            var resourceGroup = factory.GetResourceGroup(tags: tags);
            var workspace = factory.GetAnalyticsWorkspace(resourceGroupName: resourceGroup.Name, tags: tags);
            var automationAccount = factory.GetAutomationAccount(resourceGroupName: resourceGroup.Name, tags: tags);

            #region Runbooks
            // Runbook for UpdatePowershellModules
            DateTime now = DateTime.Now;
            int start = (int)now.DayOfWeek;
            int target = (int)DayOfWeek.Sunday;
            target = (target <= start ? target + 7 : target);
            DateTime nextSunday = now.AddDays(target - start);
            string publishContentLink = "https://raw.githubusercontent.com/Daniel-Jennings/PulumiTemplates/master/sub-tcms-pul-infra/Runbooks/UpdatePowershellModules.ps1";
            string runbookDescription = "A runbook to update all of the Powershell modules used in the automation account. Should be run weekly to ensure latest module code is available";
            string startTime = nextSunday.ToString("yyyy'-'MM'-'dd") + "T20:00:00-04:00";
            string scheduleDescription = "Run a task weekly on Sunday at 8PM";
            Dictionary <string, string> parameters = new Dictionary <string, string> {
                { "resourcegroupname", factory.ResourceNames["rg"][0] },
                { "automationaccountname", factory.ResourceNames["aacc"][0] }
            };
            var updatePowershellModulesRunbook = factory.GetAutomationRunbook(name: "UpdatePowershellModules", resourceGroupName: resourceGroup.Name,
                                                                              automationAccountName: automationAccount.Name, publishContentLink: publishContentLink, description: runbookDescription, runbookType: "PowerShell", tags: tags);
            var updatePowershellModulesSchedule = factory.GetAutomationSchedule(name: "WeeklySunday8PM", resourceGroupName: resourceGroup.Name, automationAccountName: automationAccount.Name,
                                                                                description: scheduleDescription, frequency: "Week", startTime: startTime, timezone: "America/Toronto", interval: 1, weekDays: new List <string> {
                "Sunday"
            });
            var updatePowershellModulesJob = factory.GetAutomationJobSchedule(resourceGroupName: resourceGroup.Name, automationAccountName: automationAccount.Name,
                                                                              runbookName: updatePowershellModulesRunbook.Name, scheduleName: updatePowershellModulesSchedule.Name,
                                                                              parameters: parameters);

            // Runbook for ShutdownSchedule
            DateTime tomorrow = now.AddDays(1);
            publishContentLink = "https://raw.githubusercontent.com/Daniel-Jennings/PulumiTemplates/master/sub-tcms-pul-infra/Runbooks/ShutdownSchedule.ps1";
            runbookDescription = "A runbook to control shutdown / startup schedules for VMs and Scale Sets";
            var shutdownScheduleRunbook = factory.GetAutomationRunbook(name: "ShutdownSchedule", resourceGroupName: resourceGroup.Name,
                                                                       automationAccountName: automationAccount.Name, publishContentLink: publishContentLink, description: runbookDescription, runbookType: "PowerShellWorkflow", tags: tags);

            // Schedule for Startup
            startTime = tomorrow.ToString("yyyy'-'MM'-'dd") + "T07:00:00-04:00";
            scheduleDescription = "Run a task daily at 7AM";
            parameters = new Dictionary <string, string> {
                { "shutdown", "false" },
                { "verboselogging", "false" }
            };
            var shutdownScheduleScheduleStartup = factory.GetAutomationSchedule(name: "Daily7AM", resourceGroupName: resourceGroup.Name, automationAccountName: automationAccount.Name,
                                                                                description: scheduleDescription, frequency: "Day", startTime: startTime, timezone: "America/Toronto", interval: 1);
            var shutdownScheduleJobStartup = factory.GetAutomationJobSchedule(resourceGroupName: resourceGroup.Name, automationAccountName: automationAccount.Name,
                                                                              runbookName: shutdownScheduleRunbook.Name, scheduleName: shutdownScheduleScheduleStartup.Name,
                                                                              parameters: parameters);

            // Schedule for Shutdown
            startTime = tomorrow.ToString("yyyy'-'MM'-'dd") + "T19:00:00-04:00";
            scheduleDescription = "Run a task daily at 7PM";
            parameters = new Dictionary <string, string> {
                { "shutdown", "true" },
                { "verboselogging", "false" }
            };
            var shutdownScheduleScheduleShutdown = factory.GetAutomationSchedule(name: "Daily7PM", resourceGroupName: resourceGroup.Name, automationAccountName: automationAccount.Name,
                                                                                 description: scheduleDescription, frequency: "Day", startTime: startTime, timezone: "America/Toronto", interval: 1);
            var shutdownScheduleJobShutdown = factory.GetAutomationJobSchedule(resourceGroupName: resourceGroup.Name, automationAccountName: automationAccount.Name,
                                                                               runbookName: shutdownScheduleRunbook.Name, scheduleName: shutdownScheduleScheduleShutdown.Name,
                                                                               parameters: parameters);
            #endregion
            // Return any outputs that may be required for subsequent steps
            return new Dictionary <string, object?>
            {
                { "resourceGroupId", resourceGroup.Id },
                { "resourceGroupName", resourceGroup.Name },
                { "workspaceId", workspace.WorkspaceId },
            };
        }));
    }