Beispiel #1
0
    public AppStack()
    {
        var config = new Config();

        var resourceGroup = new ResourceGroup("rotatesecretoneset-rg");

        var sqlAdminLogin    = config.Get("sqlAdminLogin") ?? "sqlAdmin";
        var sqlAdminPassword = new RandomUuid("sqlPassword").Result;
        var sqlServer        = new Server("sqlServer", new ServerArgs
        {
            AdministratorLogin         = sqlAdminLogin,
            AdministratorLoginPassword = sqlAdminPassword,
            ResourceGroupName          = resourceGroup.Name,
            Version = "12.0",
        });

        new FirewallRule("AllowAllWindowsAzureIps",
                         new FirewallRuleArgs
        {
            ServerName        = sqlServer.Name,
            ResourceGroupName = resourceGroup.Name,
            StartIpAddress    = "0.0.0.0",
            EndIpAddress      = "0.0.0.0",
        });

        var clientConfig = Output.Create(GetClientConfig.InvokeAsync());
        var tenantId     = clientConfig.Apply(c => c.TenantId);

        var storageAccount = new StorageAccount("storageaccount", new StorageAccountArgs
        {
            Kind = "Storage",
            ResourceGroupName = resourceGroup.Name,
            Sku = new Storage.Inputs.SkuArgs
            {
                Name = "Standard_LRS"
            },
        });

        var appInsights = new Component("appInsights", new ComponentArgs
        {
            RequestSource     = "IbizaWebAppExtensionCreate",
            ResourceGroupName = resourceGroup.Name,
            ApplicationType   = "web",
            Kind = "web",
            Tags =
            {
                //{ "[concat('hidden-link:', resourceId('Microsoft.Web/sites', parameters('functionAppName')))]", "Resource" },
            },
        });

        var secretName = config.Get("secretName") ?? "sqlPassword";
        var appService = new AppServicePlan("functionApp-appService", new AppServicePlanArgs
        {
            ResourceGroupName = resourceGroup.Name,
            Sku = new SkuDescriptionArgs
            {
                Name = "Y1",
                Tier = "Dynamic",
            },
        });

        var storageKey = Output.Tuple(resourceGroup.Name, storageAccount.Name).Apply(v =>
        {
            var task = ListStorageAccountKeys.InvokeAsync(new ListStorageAccountKeysArgs {
                AccountName = v.Item2, ResourceGroupName = v.Item1
            });
            return(Output.Create(task).Apply(t => t.Keys[0].Value));
        });

        var functionApp = new WebApp("functionApp", new WebAppArgs
        {
            Kind = "functionapp",
            ResourceGroupName = resourceGroup.Name,
            ServerFarmId      = appService.Id,
            Identity          = new ManagedServiceIdentityArgs {
                Type = ManagedServiceIdentityType.SystemAssigned
            },
            SiteConfig = new SiteConfigArgs
            {
                AppSettings =
                {
                    new NameValuePairArgs
                    {
                        Name  = "AzureWebJobsStorage",
                        Value = Output.Format($"DefaultEndpointsProtocol=https;AccountName={storageAccount.Name};AccountKey={storageKey}"),
                    },
                    new NameValuePairArgs
                    {
                        Name  = "FUNCTIONS_EXTENSION_VERSION",
                        Value = "~3",
                    },
                    new NameValuePairArgs
                    {
                        Name  = "FUNCTIONS_WORKER_RUNTIME",
                        Value = "dotnet",
                    },
                    new NameValuePairArgs
                    {
                        Name  = "WEBSITE_CONTENTAZUREFILECONNECTIONSTRING",
                        Value = Output.Format($"DefaultEndpointsProtocol=https;AccountName={storageAccount.Name};EndpointSuffix=core.windows.net;AccountKey={storageKey}"),
                    },
                    new NameValuePairArgs
                    {
                        Name  = "WEBSITE_NODE_DEFAULT_VERSION",
                        Value = "~10",
                    },
                    new NameValuePairArgs
                    {
                        Name  = "APPINSIGHTS_INSTRUMENTATIONKEY",
                        Value = appInsights.InstrumentationKey,
                    },
                },
            },
        });

        var functionAppSourceControl = new WebAppSourceControl("functionApp-sourceControl",
                                                               new WebAppSourceControlArgs
        {
            Name = functionApp.Name,
            IsManualIntegration = true,
            Branch            = "main",
            RepoUrl           = config.Get("functionAppRepoURL") ?? "https://github.com/Azure-Samples/KeyVault-Rotation-SQLPassword-Csharp.git",
            ResourceGroupName = resourceGroup.Name,
        });

        var webAppAppService = new AppServicePlan("webApp-appService", new AppServicePlanArgs
        {
            ResourceGroupName = resourceGroup.Name,
            Sku = new SkuDescriptionArgs
            {
                Name = "F1",
            },
        });

        var webApp = new WebApp("webApp", new WebAppArgs
        {
            Kind = "app",
            ResourceGroupName = resourceGroup.Name,
            ServerFarmId      = webAppAppService.Id,
            Identity          = new ManagedServiceIdentityArgs {
                Type = ManagedServiceIdentityType.SystemAssigned
            },
        });

        var keyVault = new Vault("keyVault", new VaultArgs
        {
            Properties = new VaultPropertiesArgs
            {
                AccessPolicies =
                {
                    new AccessPolicyEntryArgs
                    {
                        TenantId    = tenantId,
                        ObjectId    = functionApp.Identity.Apply(i => i !.PrincipalId),
                        Permissions = new PermissionsArgs
                        {
                            Secrets ={ "get",               "list", "set" },
                        },
                    },
Beispiel #2
0
    public TdStack()
    {
        string stackName = Pulumi.Deployment.Instance.StackName;

        Config pulumiConfig = new();

        var sqlDatabaseDbAdminId       = pulumiConfig.Require("sql-server-td-db-admin-id");
        var sqlDatabaseDbAdminPassword = pulumiConfig.RequireSecret("sql-server-td-db-admin-password");

        var sqlDatabaseDbUserId       = pulumiConfig.Require("sql-server-td-db-user-id");
        var sqlDatabaseDbUserPassword = pulumiConfig.RequireSecret("sql-server-td-db-user-password");

        var defaultEmailFrom    = pulumiConfig.Require("default-email-from");
        var emailServerHost     = pulumiConfig.Require("email-server-host");
        var emailServerPort     = pulumiConfig.Require("email-server-port");
        var emailServerUserName = pulumiConfig.Require("email-server-userName");
        var emailServerPassword = pulumiConfig.RequireSecret("email-server-password");

        var jwtSecretKey = pulumiConfig.RequireSecret("jwt-secret-key");

        var azureDevOpsAgentVMIPAddress = pulumiConfig.Require("azure-dev-ops-agent-vm-ip");

        ResourceGroup resourceGroup = new($"td-{stackName}", new ResourceGroupArgs
        {
            ResourceGroupName = $"td-{stackName}"
        }, options : new() { ImportId = $"/subscriptions/{GetClientConfig.InvokeAsync().GetAwaiter().GetResult().SubscriptionId}/resourceGroups/td-test" });

        Workspace appInsightsWorkspace = new($"insights-wkspc-td-{stackName}", new()
        {
            WorkspaceName = $"insights-wkspc-td-{stackName}",
            ResourceGroupName = resourceGroup.Name,
            Location = resourceGroup.Location,
            RetentionInDays = 30
        });

        AppInsights appInsights = new($"app-insights-td-{stackName}", new()
        {
            ResourceName = $"app-insights-td-{stackName}",
            ResourceGroupName = resourceGroup.Name,
            Location = resourceGroup.Location,
            ApplicationType = AppInsightsWebApplicationType.Web,
            Kind = "web",
            IngestionMode = AppInsightsIngestionMode.LogAnalytics,
            DisableIpMasking = true,
            WorkspaceResourceId = Output.Tuple(resourceGroup.Name, appInsightsWorkspace.Name).Apply(t =>
            {
                (string resourceGroupName, string workspaceName) = t;
                return(GetWorkspace.InvokeAsync(new GetWorkspaceArgs {
                    ResourceGroupName = resourceGroupName, WorkspaceName = workspaceName
                }));
            }).Apply(workspace => workspace.Id)
        });

        SqlServer sqlServer = new($"sql-server-td-{stackName}", new()
        {
            ServerName = $"sql-server-td-{stackName}",
            ResourceGroupName = resourceGroup.Name,
            Location = resourceGroup.Location,
            AdministratorLogin = sqlDatabaseDbAdminId,
            AdministratorLoginPassword = sqlDatabaseDbAdminPassword
        });

        SqlDatabase sqlDatabase = new($"sql-database-td-{stackName}", new()
        {
            DatabaseName = $"sql-database-td-{stackName}",
            ResourceGroupName = resourceGroup.Name,
            Location = resourceGroup.Location,
            ServerName = sqlServer.Name,
            Sku = new SqlDatabaseSkuArgs
            {
                Tier = "Basic",
                Name = "Basic",
                Capacity = 5
            }
        });

        AppServicePlan appServicePlan = new($"app-plan-td-{stackName}", new()
        {
            Name = $"app-plan-td-{stackName}",
            ResourceGroupName = resourceGroup.Name,
            Location = resourceGroup.Location,
            Kind = "Linux",
            Reserved = true,
            Sku = new SkuDescriptionArgs
            {
                Tier = "Basic",
                Name = "B1",
                Size = "B1",
                Capacity = 1,
                Family = "B"
            }
        });

        string vaultName = $"vault-td-{stackName}";
        string sqlDatabaseConnectionStringSecretName = $"sql-connection-secret";
        string blobStorageConnectionStringSecretName = $"blob-connection-secret";
        string emailServerPasswordSecretName         = "email-server-password-secret";
        string jwtSecretKeySecretName = "jwt-secret-key-secret";

        WebApp webApp = new($"app-service-td-{stackName}", new()
        {
            Name = $"app-service-td-{stackName}",
            ResourceGroupName = resourceGroup.Name,
            Location = resourceGroup.Location,
            ServerFarmId = appServicePlan.Id,
            ClientAffinityEnabled = false,
            HttpsOnly = true,
            Identity = new WebAppManagedServiceIdentityArgs()
            {
                Type = ManagedServiceIdentityType.SystemAssigned
            },
            SiteConfig = new SiteConfigArgs
            {
                Use32BitWorkerProcess = false,
                AlwaysOn = true,
                Http20Enabled = true,
                WebSocketsEnabled = true,
                NetFrameworkVersion = "v6.0",
                FtpsState = FtpsState.Disabled,
                LinuxFxVersion = "DOTNETCORE|6.0",
                AppCommandLine = "dotnet TodoTemplate.Api.dll",
                AppSettings = new()
                {
                    new NameValuePairArgs {
                        Name = "ApplicationInsights__InstrumentationKey", Value = appInsights.InstrumentationKey
                    },
                    new NameValuePairArgs {
                        Name = "APPINSIGHTS_INSTRUMENTATIONKEY", Value = appInsights.InstrumentationKey
                    },
                    new NameValuePairArgs {
                        Name = "ASPNETCORE_ENVIRONMENT", Value = stackName == "test" ? "Test" : "Production"
                    },
                    new NameValuePairArgs {
                        Name = "APPLICATIONINSIGHTS_CONNECTION_STRING", Value = appInsights.ConnectionString
                    },
                    new NameValuePairArgs {
                        Name = "APPINSIGHTS_PROFILERFEATURE_VERSION", Value = "disabled"
                    },
                    new NameValuePairArgs {
                        Name = "APPINSIGHTS_SNAPSHOTFEATURE_VERSION", Value = "disabled"
                    },
                    new NameValuePairArgs {
                        Name = "ApplicationInsightsAgent_EXTENSION_VERSION", Value = "~3"
                    },
                    new NameValuePairArgs {
                        Name = "XDT_MicrosoftApplicationInsights_BaseExtensions", Value = "~1"
                    },
                    new NameValuePairArgs {
                        Name = "InstrumentationEngine_EXTENSION_VERSION", Value = "~1"
                    },
                    new NameValuePairArgs {
                        Name = "SnapshotDebugger_EXTENSION_VERSION", Value = "disabled"
                    },
                    new NameValuePairArgs {
                        Name = "XDT_MicrosoftApplicationInsights_Mode", Value = "recommended"
                    },
                    new NameValuePairArgs {
                        Name = "XDT_MicrosoftApplicationInsights_PreemptSdk", Value = "disabled"
                    },
                    new NameValuePairArgs {
                        Name = "AppSettings__EmailSettings__DefaulFromEmail", Value = defaultEmailFrom
                    },
                    new NameValuePairArgs {
                        Name = "AppSettings__EmailSettings__Host", Value = emailServerHost
                    },
                    new NameValuePairArgs {
                        Name = "AppSettings__EmailSettings__Port", Value = emailServerPort
                    },
                    new NameValuePairArgs {
                        Name = "AppSettings__EmailSettings__UserName", Value = emailServerUserName
                    },
                    new NameValuePairArgs
                    {
                        Name = "AppSettings__EmailSettings__Password",
                        Value = $"@Microsoft.KeyVault(VaultName={vaultName};SecretName={emailServerPasswordSecretName})"
                    },
                    new NameValuePairArgs
                    {
                        Name = "AppSettings__JwtSettings__SecretKey",
                        Value = $"@Microsoft.KeyVault(VaultName={vaultName};SecretName={jwtSecretKeySecretName})"
                    },
                },
                ConnectionStrings = new()
                {
                    new ConnStringInfoArgs
                    {
                        Name = "SqlServerConnectionString",
                        Type = ConnectionStringType.SQLAzure,
                        ConnectionString = $"@Microsoft.KeyVault(VaultName={vaultName};SecretName={sqlDatabaseConnectionStringSecretName})"
                    },
                    new ConnStringInfoArgs
                    {
                        Name = "AzureBlobStorageConnectionString",
                        Type = ConnectionStringType.Custom,
                        ConnectionString = $"@Microsoft.KeyVault(VaultName={vaultName};SecretName={blobStorageConnectionStringSecretName})"
                    }
                }
            }
        });

        StorageAccount blobStorageAccount = new($"storageacctd{stackName}", new()
        {
            AccountName = $"storageacctd{stackName}",
            ResourceGroupName = resourceGroup.Name,
            Location = resourceGroup.Location,
            AccessTier = AccessTier.Hot,
            Kind = StorageKind.BlobStorage,
            Sku = new StorageAccountSkuArgs
            {
                Name = StorageSkuName.Standard_LRS
            }
        });

        BlobContainer attachmentsContainer = new("attachments", new()
        {
            ResourceGroupName = resourceGroup.Name,
            AccountName = blobStorageAccount.Name,
            ContainerName = $"attachments",
            PublicAccess = PublicAccess.None
        });

        new SqlServerFirewallRule($"fw-{stackName}-azure-dev-ops-agent-vm-ip", new()
        {
            Name              = $"fw-{stackName}-azure-dev-ops-agent-vm-ip",
            FirewallRuleName  = $"fw-{stackName}-azure-dev-ops-agent-vm-ip",
            EndIpAddress      = azureDevOpsAgentVMIPAddress,
            ResourceGroupName = resourceGroup.Name,
            ServerName        = sqlServer.Name,
            StartIpAddress    = azureDevOpsAgentVMIPAddress
        });

        Output.Tuple(resourceGroup.Name, webApp.Name).Apply(t =>
        {
            (string resourceGroupName, string webAppName) = t;

            Output.Create(GetWebApp.InvokeAsync(new() { Name = webAppName, ResourceGroupName = resourceGroupName }))
            .Apply(webAppToGetIPAddresses =>
            {
                var ipAddresses = webAppToGetIPAddresses.PossibleOutboundIpAddresses;

                foreach (var ipAddress in ipAddresses.Split(','))
                {
                    new SqlServerFirewallRule($"fw-{stackName}-{ipAddress}", new()
                    {
                        Name              = $"fw-{stackName}-{ipAddress}",
                        FirewallRuleName  = $"fw-{stackName}-{ipAddress}",
                        EndIpAddress      = ipAddress,
                        ResourceGroupName = resourceGroup.Name,
                        ServerName        = sqlServer.Name,
                        StartIpAddress    = ipAddress
                    });
                }

                return(string.Empty);
            });

            return(string.Empty);
        });

        Vault vault = new Vault($"vault-td-{stackName}", new()
        {
            ResourceGroupName = resourceGroup.Name,
            Location          = resourceGroup.Location,
            VaultName         = vaultName,
            Properties        = new VaultPropertiesArgs()
            {
                Sku = new VaultSkuArgs {
                    Name = VaultSkuName.Standard, Family = SkuFamily.A
                },
                TenantId                     = Output.Create(GetClientConfig.InvokeAsync()).Apply(clientConfig => clientConfig.TenantId),
                EnabledForDeployment         = true,
                EnabledForDiskEncryption     = true,
                EnabledForTemplateDeployment = true,
                EnableSoftDelete             = false,
                AccessPolicies               = new List <AccessPolicyEntryArgs>
                {
                    new AccessPolicyEntryArgs
                    {
                        TenantId = Output.Create(GetClientConfig.InvokeAsync()).Apply(clientConfig => clientConfig.TenantId),
                        ObjectId = Output.Tuple(resourceGroup.Name, webApp.Name).Apply(t =>
                        {
                            (string resourceGroupName, string webAppName) = t;
                            return(GetWebApp.InvokeAsync(new GetWebAppArgs {
                                ResourceGroupName = resourceGroupName, Name = webAppName
                            }));
                        }).Apply(app => app.Identity !.PrincipalId),
                        Permissions = new PermissionsArgs
                        {
                            Secrets =
                            {
                                "get"
                            }
                        }
                    }
                }
            }
        });

        Secret jwtSecretKeySecret = new(jwtSecretKeySecretName, new()
        {
            ResourceGroupName = resourceGroup.Name,
            VaultName = vault.Name,
            SecretName = jwtSecretKeySecretName,
            Properties = new SecretPropertiesArgs
            {
                Value = jwtSecretKey
            }
        });

        Secret emailServerPasswordSecret = new(emailServerPasswordSecretName, new()
        {
            ResourceGroupName = resourceGroup.Name,
            VaultName = vault.Name,
            SecretName = emailServerPasswordSecretName,
            Properties = new SecretPropertiesArgs
            {
                Value = emailServerPassword
            }
        });

        Secret sqlDatabaseConnectionStringSecret = new(sqlDatabaseConnectionStringSecretName, new()
        {
            ResourceGroupName = resourceGroup.Name,
            VaultName = vault.Name,
            SecretName = sqlDatabaseConnectionStringSecretName,
            Properties = new SecretPropertiesArgs
            {
                Value = Output.Tuple(sqlServer.Name, sqlDatabase.Name, sqlDatabaseDbUserPassword).Apply(t =>
                {
                    (string _sqlServer, string _sqlDatabase, string _sqlDatabasePassword) = t;
                    return($"Data Source=tcp:{_sqlServer}.database.windows.net;Initial Catalog={_sqlDatabase};User ID={sqlDatabaseDbUserId};Password={_sqlDatabasePassword};Application Name=Todo;Encrypt=True;");
                })
            }
        });

        var attachmentsContainerConnectionString = Output.Tuple(resourceGroup.Name, blobStorageAccount.Name, attachmentsContainer.Name)
                                                   .Apply(t =>
        {
            (string resourceGroupName, string blobStorageAccountName, string attachmentsContainerName) = t;

            var result = Output.Create(GetStorageAccountPrimaryKey(resourceGroupName, blobStorageAccountName))
                         .Apply(blobStorageAccountKey =>
            {
                BlobSasBuilder blobSasBuilder = new BlobSasBuilder
                {
                    BlobContainerName = attachmentsContainerName,
                    Protocol          = SasProtocol.Https,
                    StartsOn          = DateTimeOffset.Parse("2022-01-01T22:00:00Z"),
                    ExpiresOn         = DateTimeOffset.Parse("2032-01-01T22:00:00Z"),
                    Resource          = "c"
                };

                blobSasBuilder.SetPermissions(BlobSasPermissions.Read | BlobSasPermissions.Create | BlobSasPermissions.Delete);

                var blobStorageConnectionString = $"https://{blobStorageAccountName}.blob.core.windows.net/{attachmentsContainerName}?{blobSasBuilder.ToSasQueryParameters(new StorageSharedKeyCredential(blobStorageAccountName, blobStorageAccountKey))}";

                return(blobStorageConnectionString);
            });

            return(result);
        });

        Secret blobStorageConnectionStringSecret = new(blobStorageConnectionStringSecretName, new()
        {
            ResourceGroupName = resourceGroup.Name,
            VaultName = vault.Name,
            SecretName = blobStorageConnectionStringSecretName,
            Properties = new SecretPropertiesArgs
            {
                Value = attachmentsContainerConnectionString
            }
        });
    }