Beispiel #1
0
    public KeyVaultStack()
    {
        // Get current Subscription
        var currentSubscription = Output.Create(GetSubscription.InvokeAsync());
        var tenantId            = currentSubscription.Apply(currentSubscription => currentSubscription.TenantId);

        // Get current Client Config
        var currentClient = Output.Create(GetClientConfig.InvokeAsync());
        var objectId      = currentClient.Apply(currentClient => currentClient.ObjectId);

        var config            = new Pulumi.Config();
        var resourceGroupName = config.Require("resource_group_name");
        var keyVaultName      = config.Require("key_vault_name");

        // Create an Azure Resource Group
        var resourceGroup = new ResourceGroup(resourceGroupName);

        // Create an Azure Key Vault
        var keyVault = new KeyVault(keyVaultName, new KeyVaultArgs
        {
            ResourceGroupName = resourceGroup.Name,
            SkuName           = "standard",
            TenantId          = tenantId,
            AccessPolicies    =
            {
                new KeyVaultAccessPolicyArgs
                {
                    TenantId          = tenantId,
                    ObjectId          = objectId,
                    SecretPermissions ={ "list",                         "get" }
                }
            }
        });

        this.VaultUri = keyVault.VaultUri;
    }
    public WebAppStack()
    {
        var resourceGroup = new ResourceGroup("rg-easy-azure-webapp");

        var clientConfig = Output.Create(GetClientConfig.InvokeAsync());

        var tenantId         = clientConfig.Apply(config => config.TenantId);
        var currentPrincipal = clientConfig.Apply(config => config.ObjectId);

        var solutionRoot = System.Environment.GetEnvironmentVariable("SOLUTION_ROOT_DIRECTORY");

        var storageAccount = new Account("storage", new AccountArgs
        {
            ResourceGroupName      = resourceGroup.Name,
            AccountReplicationType = "LRS",
            AccountTier            = "Standard",
        });

        var storageContainer = new Container("files", new ContainerArgs
        {
            StorageAccountName  = storageAccount.Name,
            ContainerAccessType = "private",
        });

        var codeBlob = new Blob("zip", new BlobArgs
        {
            StorageAccountName   = storageAccount.Name,
            StorageContainerName = storageContainer.Name,
            Type = "Block",

            Source = new FileArchive(Path.Join(solutionRoot, "src/Services/EasyAzureWebApp/bin/Debug/netcoreapp3.1/publish"))
        });

        var keyVault = new KeyVault("key-vault", new KeyVaultArgs
        {
            ResourceGroupName = resourceGroup.Name,
            SkuName           = "standard",
            TenantId          = tenantId,
            SoftDeleteEnabled = true,
        });

        var keyVaultPolicy = new AccessPolicy("key-vault-policy", new AccessPolicyArgs
        {
            KeyVaultId        = keyVault.Id,
            TenantId          = tenantId,
            ObjectId          = currentPrincipal,
            SecretPermissions = new[] { "delete", "get", "list", "set" },
        });

        var codeBlobSecret = new Secret("zip-secret", new SecretArgs
        {
            KeyVaultId = keyVault.Id,
            Value      = SharedAccessSignature.SignedBlobReadUrl(codeBlob, storageAccount),
        });

        var codeBlobSecretUrl = Output.All(keyVault.VaultUri, codeBlobSecret.Name, codeBlobSecret.Version)
                                .Apply(d => $"{d[0]}secrets/{d[1]}/{d[2]}");

        var appServicePlan = new Plan("easy-azure-webapp-plan", new PlanArgs
        {
            ResourceGroupName = resourceGroup.Name,
            Kind = "App",
            Sku  = new PlanSkuArgs
            {
                Tier = "Basic",
                Size = "B1",
            },
        });

        var appService = new AppService("easy-azure-webapp", new AppServiceArgs
        {
            ResourceGroupName = resourceGroup.Name,
            AppServicePlanId  = appServicePlan.Id,
            Identity          = new AppServiceIdentityArgs
            {
                Type = "SystemAssigned",
            },
            AppSettings = new InputMap <string>
            {
                { "WEBSITE_RUN_FROM_ZIP", codeBlobSecretUrl.Apply(url => $"@Microsoft.KeyVault(SecretUri={url})") },
            }
        });

        var appServiceGet = AppService.Get("easy-azure-webapp-get", appService.Id,
                                           new AppServiceState
        {
            ResourceGroupName = resourceGroup.Name,
            AppServicePlanId  = appServicePlan.Id,
        },
                                           new CustomResourceOptions
        {
            DependsOn = appService,
        }
                                           );

        var principalId = appServiceGet.Identity.Apply(id => id.PrincipalId !);

        var policy = new AccessPolicy("app-policy", new AccessPolicyArgs
        {
            KeyVaultId        = keyVault.Id,
            TenantId          = tenantId,
            ObjectId          = principalId,
            SecretPermissions = "get",
        });

        var subscriptionOutput = Output.Create(GetSubscription.InvokeAsync());
        var scope = Output.All(
            subscriptionOutput.Apply(s => s.SubscriptionId),
            resourceGroup.Name,
            storageAccount.Name,
            storageContainer.Name
            ).Apply(s => $"/subscriptions/{s[0]}/resourcegroups/{s[1]}/providers/Microsoft.Storage/storageAccounts/{s[2]}/blobServices/default/containers/{s[3]}");

        var codeBlobPermission = new Assignment("read-code-blob", new AssignmentArgs
        {
            PrincipalId        = principalId !,
            Scope              = scope,
            RoleDefinitionName = "Storage Blob Data Reader",
        },
        public MyStack()
        {
            var env = Deployment.Instance.StackName;

            // Create an Azure Resource Group
            var resourceGroup = new ResourceGroup($"{env}-skywalker-website");

            // Create an Azure Storage Account
            var storageAccount = new Account("storage", new AccountArgs
            {
                ResourceGroupName      = resourceGroup.Name,
                AccountReplicationType = "LRS",
                AccountTier            = "Standard",
            });

            // Create a container registry.
            var registry = new Registry("registry", new RegistryArgs
            {
                ResourceGroupName = resourceGroup.Name,
                Sku          = "Basic",
                AdminEnabled = true
            });

            // Create a username for SQL Server.
            var sqlUserName = "******";

            // Create a random password for SQL Server.
            var sqlPassword = new RandomPassword("password", new RandomPasswordArgs
            {
                Length  = 20,
                Special = true,
            }).Result;

            // Create a Sql Server.
            var sqlServer = new SqlServer("sql", new SqlServerArgs
            {
                ResourceGroupName          = resourceGroup.Name,
                AdministratorLogin         = sqlUserName,
                AdministratorLoginPassword = sqlPassword,
                Version = "12.0",
            });

            // Create a database.
            var database = new Database("skywalker", new DatabaseArgs
            {
                ResourceGroupName             = resourceGroup.Name,
                ServerName                    = sqlServer.Name,
                RequestedServiceObjectiveName = "S0",
            });

            var dbConnectionString = Output.Tuple(sqlServer.Name, database.Name, sqlPassword).Apply(x =>
            {
                (var server, var dbName, string pwd) = x;
                return
                ($"Server= tcp:{server}.database.windows.net;initial catalog={dbName};user ID={sqlUserName};password={pwd};Min Pool Size=0;Max Pool Size=30;Persist Security Info=true;");
            });

            // Create an app service plan.
            var plan = new Plan($"skywalker-apps", new PlanArgs
            {
                ResourceGroupName = resourceGroup.Name,
                Kind     = "Linux",
                Reserved = true,
                Sku      = new PlanSkuArgs
                {
                    Tier = "Basic",
                    Size = "B1"
                }
            });

            // Create an app service.
            var appService = new AppService($"skywalker-website", new AppServiceArgs
            {
                ResourceGroupName = resourceGroup.Name,
                AppServicePlanId  = plan.Id,
                AppSettings       = new InputMap <string>
                {
                    ["WEBSITES_ENABLE_APP_SERVICE_STORAGE"] = "false",
                    ["WEBSITE_HTTPLOGGING_RETENTION_DAYS"]  = "1",
                    ["DOCKER_REGISTRY_SERVER_URL"]          = registry.LoginServer.Apply(x => $"https://{x}"),
                    ["DOCKER_REGISTRY_SERVER_USERNAME"]     = registry.AdminUsername,
                    ["DOCKER_REGISTRY_SERVER_PASSWORD"]     = registry.AdminPassword,
                    ["DOCKER_ENABLE_CI"] = "false",
                    ["WEBSITES_PORT"]    = "80",
                    ["ORCHARDCORE__ORCHARDCORE_DATAPROTECTION_AZURE__CONNECTIONSTRING"] =
                        storageAccount.PrimaryConnectionString,
                    ["ORCHARDCORE__ORCHARDCORE_MEDIA_AZURE__CONNECTIONSTRING"]  = storageAccount.PrimaryConnectionString,
                    ["ORCHARDCORE__ORCHARDCORE_MEDIA_SHELLS__CONNECTIONSTRING"] =
                        storageAccount.PrimaryConnectionString,
                },
                ConnectionStrings = new AppServiceConnectionStringArgs
                {
                    Name  = "db",
                    Type  = "SQLAzure",
                    Value = dbConnectionString,
                },
                Logs = new AppServiceLogsArgs
                {
                    HttpLogs = new AppServiceLogsHttpLogsArgs
                    {
                        FileSystem = new AppServiceLogsHttpLogsFileSystemArgs
                        {
                            RetentionInDays = 1,
                            RetentionInMb   = 35
                        }
                    }
                },
                SiteConfig = new AppServiceSiteConfigArgs
                {
                    AlwaysOn       = true,
                    LinuxFxVersion = registry.LoginServer.Apply(x => $"DOCKER|{x}/skywalker-website:latest"),
                },
                HttpsOnly = true
            });

            var appName = appService.Name;

            // Create a service principal for GitHub Actions to interact with the App Service.
            var adApp = new Application("skywalker-website");

            var adSp = new ServicePrincipal(
                "skywalker-sp",
                new ServicePrincipalArgs
            {
                ApplicationId = adApp.ApplicationId,
            });

            var adSpPassword = new ServicePrincipalPassword("skywalker-sp-pwd", new ServicePrincipalPasswordArgs
            {
                ServicePrincipalId = adSp.Id,
                Value   = "!Test1234",
                EndDate = "2099-01-01T00:00:00Z",
            });

            // Grant networking permissions to the SP (needed e.g. to provision Load Balancers).
            var assignment = new Assignment("skywalker-sp-role-assignment", new AssignmentArgs
            {
                PrincipalId        = adSp.Id,
                Scope              = resourceGroup.Id,
                RoleDefinitionName = "Owner"
            });

            var azureCredentials = Output.Tuple(
                adApp.ApplicationId,
                Output.Create("!Test1234"))
                                   .Apply(x =>
            {
                var currentSubscription = GetSubscription.InvokeAsync().Result;

                var model = new
                {
                    clientId       = x.Item1,
                    clientSecret   = x.Item2,
                    subscriptionId = currentSubscription.SubscriptionId,
                    tenantId       = currentSubscription.TenantId,
                };

                return(JsonConvert.SerializeObject(model));
            });

            StorageConnectionString  = storageAccount.PrimaryConnectionString;
            DatabaseConnectionString = dbConnectionString;
            RegistryServer           = registry.LoginServer;
            RegistryRepo             = registry.LoginServer;
            RegistryUser             = registry.AdminUsername;
            RegistryPassword         = registry.AdminPassword;
            AzureCredentials         = azureCredentials;
            AppName    = appName;
            WebsiteUrl = appService.DefaultSiteHostname.Apply(x => $"https://{x}");

            // Push secrets to GitHub.
            var variablePrefix  = env.ToUpperInvariant();
            var gitHubVariables = new GitHubVariables("github-variables", new GitHubVariablesArgs
            {
                Variables = new Dictionary <string, Input <string> >
                {
                    [$"{variablePrefix}_DOCKER_REGISTRY"]   = RegistryServer,
                    [$"{variablePrefix}_DOCKER_REPO"]       = RegistryRepo,
                    [$"{variablePrefix}_DOCKER_USER"]       = RegistryUser,
                    [$"{variablePrefix}_DOCKER_PASSWORD"]   = RegistryPassword,
                    [$"{variablePrefix}_APP_NAME"]          = AppName,
                    [$"{variablePrefix}_AZURE_CREDENTIALS"] = azureCredentials
                }
            });
        }