From 9b28089d246cd3524cb8187333f61f2894859ffa Mon Sep 17 00:00:00 2001 From: Hindrik Bruinsma Date: Wed, 13 Mar 2024 13:44:48 +0100 Subject: [PATCH] Add issue template to create an environment --- .cfg_template/deployer.tfvars | 237 ++++++++++++++++++ .cfg_template/library.tfvars | 11 + .../ISSUE_TEMPLATE/create_environment.yaml | 39 +++ .github/workflows/create-environment.tpl | 1 + .github/workflows/create-environment.yaml | 123 +++++++++ 5 files changed, 411 insertions(+) create mode 100644 .cfg_template/deployer.tfvars create mode 100644 .cfg_template/library.tfvars create mode 100644 .github/ISSUE_TEMPLATE/create_environment.yaml create mode 100644 .github/workflows/create-environment.tpl create mode 100644 .github/workflows/create-environment.yaml diff --git a/.cfg_template/deployer.tfvars b/.cfg_template/deployer.tfvars new file mode 100644 index 0000000..f4b4b57 --- /dev/null +++ b/.cfg_template/deployer.tfvars @@ -0,0 +1,237 @@ +########################################################################################## +# # +# This sample defines an standard control plane deployment with # +# 1 Deployer (deployer_count = 1) # +# Azure Firewall (firewall_deployment = true) # +# Azure Bastion (bastion_deployment = true) # +# Azure Web App (use_webapp = false) # +# # +########################################################################################## + +# The automation supports both creating resources (greenfield) or using existing resources (brownfield) +# For the greenfield scenario the automation defines default names for resources, +# if there is a XXXXname variable then the name is customizable +# for the brownfield scenario the Azure resource identifiers for the resources must be specified + +######################################################################################### +# # +# Environment definitioms # +# # +######################################################################################### +environment = "@@ENV@@" +# The location/region value is a mandatory field, it is used to control where the resources are deployed +location = "@@REGION@@" + +# RESOURCEGROUP +# The two resource group name and arm_id can be used to control the naming and the creation of the resource group +# The resourcegroup_name value is optional, it can be used to override the name of the resource group that will be provisioned +# The resourcegroup_name arm_id is optional, it can be used to provide an existing resource group for the deployment +#resourcegroup_name="" +#resourcegroup_arm_id="" + +resourcegroup_tags = { + Control_plane = "@@REGION_DISPLAY_NAME@@" +} + +######################################################################################### +# # +# Networking # +# # +######################################################################################### +# The deployment automation supports two ways of providing subnet information. +# 1. Subnets are defined as part of the workload zone deployment +# In this model multiple SAP System share the subnets +# 2. Subnets are deployed as part of the SAP system +# In this model each SAP system has its own sets of subnets +# +# The automation supports both creating the subnets (greenfield) or using existing subnets (brownfield) +# For the greenfield scenario the subnet address prefix must be specified whereas +# for the brownfield scenario the Azure resource identifier for the subnet must be specified + + +#management_network_name="" +management_network_logical_name = "@@VNET@@" +#management_network_arm_id="" +management_network_address_space = "10.170.20.0/24" + +# management subnet +# If defined these parameters control the subnet name and the subnet prefix +# management_subnet_name is an optional parameter and should only be used if the default naming is not acceptable +#management_subnet_name="" + +# management_subnet_address_prefix is a mandatory parameter if the subnets are not defined in the workload or if existing subnets are not used +management_subnet_address_prefix = "10.170.20.64/28" +# management_subnet_arm_id is an optional parameter that if provided specifies Azure resource identifier for the existing subnet to use +#management_subnet_arm_id="/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/MGMT-WEEU-MGMT01-INFRASTRUCTURE/providers/Microsoft.Network/virtualNetworks/MGMT-WEEU-MGMT01-vnet/subnets/MGMT-WEEU-MGMT01-subnet_management" + +# management_subnet_nsg_arm_id is an optional parameter that if provided specifies Azure resource identifier for the existing network security group to use +#management_subnet_nsg_arm_id="/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/MGMT-WEEU-MGMT01-INFRASTRUCTURE/providers/Microsoft.Network/networkSecurityGroups/MGMT-WEEU-SAP01_managementSubnet-nsg" + +# management_subnet_nsg_allowed_ips is an optional parameter that if provided specifies a list of allowed IP ranges for the NSG + +######################################################################################### +# # +# Azure Firewall # +# # +######################################################################################### + +# firewall_deployment is a boolean flag controlling if an Azure firewall is to be deployed in the deployer VNet +firewall_deployment = false + +# management_firewall_subnet_arm_id is an optional parameter that if provided specifies +# Azure resource identifier for the existing firewall subnet +# management_firewall_subnet_arm_id= "" + +# management_firewall_subnet_address_prefix is a mandatory parameter +management_firewall_subnet_address_prefix = "10.170.20.0/26" + +# firewall_rule_subnets is an optional list of subnets to be added to the Azure firewall +#firewall_rule_subnets=[] + +# firewall_rule_allowed_ipaddresses is an optional list of IP Addresses to be added to the Azure firewall +#firewall_rule_allowed_ipaddresses=[] + +######################################################################################### +# # +# Azure Bastion # +# # +######################################################################################### + +# bastion_deployment is a boolean flag controlling if Azure bastion is to be deployed in the deployer VNet +bastion_deployment = false + +# management_bastion_subnet_arm_id is an optional parameter that if provided specifies Azure resource +# identifier for the existing AzureBastion subnet +# management_bastion_subnet_arm_id= "" + +# management_bastion_subnet_address_prefix is a mandatory parameter if bastion is deployed and if the subnets are not defined in the workload or if existing subnets are not used +management_bastion_subnet_address_prefix = "10.170.20.128/26" + +######################################################################################### +# # +# Azure Web App # +# # +######################################################################################### + +# use_webapp is a boolean flag controlling if configuration Web App is to be deployed in the deployer VNet +use_webapp = false + +# webapp_subnet_arm_id is an optional parameter that if provided specifies Azure resource +# identifier for the existing subnet +# webapp_subnet_arm_id= "" + +# webapp_subnet_address_prefix is a mandatory parameter if the Web App is to be deployed +webapp_subnet_address_prefix = "10.170.20.80/28" + + + +######################################################################################### +# # +# Deployer VM information # +# # +######################################################################################### + +# deployer_enable_public_ip defines if the deployers will be deployed with a public IP address +deployer_enable_public_ip = true + +# deployer_count is an optional parameter that specifies the number of deployer VMs to be provisioned +deployer_count=1 + +# deployer_size is optional and defines the virtual machine SKU +#deployer_size="Standard_D4ds_v4" + +# deployer_disk_type is optional and defines the virtual machine disk type +#deployer_disk_type"="Premium_LRS" + +# deployer_use_DHCP is a boolean flag controlling if Azure subnet provided IP addresses should be used (true) +deployer_use_DHCP = true + +# private_ip_address if defined will provide the IP addresses for the network interface cards +#private_ip_address=[""] + +# +# The deployer_image defines the Virtual machine image to use, if source_image_id is specified the deployment will use the custom image provided, in this case os_type must also be specified + +deployer_image = { + "type" = "marketplace" + "os_type" = "Linux" + "source_image_id" = "" + "publisher" = "Canonical" + "offer" = "0001-com-ubuntu-server-jammy" + "sku" = "22_04-lts-gen2" + "version" = "latest" +} + +# Use this field if you are using a marketplace image that has a plan attached to it +plan = { + "use" = false + "name" = "" + "publisher" = "" + "product" = "" + } + +# deployer_diagnostics_account_arm_id defines the diagnosting storage account for the deployer +# deployer_diagnostics_account_arm_id = "" + +# deployer_authentication_type defines the authentication type for the deployer virtual machine +#deployer_authentication_type="key" + +# use_spn defines if the deployments are performed using Service Principals or the deployer's managed identiry, true=SPN, false=MSI +# use_spn = true + +# user_assigned_identity_id defines the user assigned identity that will be assigned to the deployers +#user_assigned_identity_id="/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/XXXXXXXX/providers/Microsoft.ManagedIdentity/userAssignedIdentities/xxxxxxxxxx" + + +######################################################################################### +# # +# Key Vault information # +# # +######################################################################################### + +# These variables define the keyvault that is used to store the deployer credentials +# user_keyvault_id is the Azure resource identifier for the keyvault that will contain the credentials keys +#user_keyvault_id="" + +# deployer_private_key_secret_name if provided contains the secret name for the private key +#deployer_private_key_secret_name="" + +# deployer_public_key_secret_name if provided contains the secret name for the public key +#deployer_public_key_secret_name="" + +# deployer_username_secret_name if provided contains the secret name for the username +#deployer_username_secret_name="" + +# deployer_password_secret_name if provided contains the secret name for the password +#deployer_password_secret_name="" + +enable_purge_control_for_keyvaults = false + +# List of object IDs to add to key vault policies" +#additional_users_to_add_to_keyvault_policies=["xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", "yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy"] + + +######################################################################################### +# # +# Miscallaneous settings # +# # +######################################################################################### + +# deployer_assign_subscription_permissions is a boolean flag controlling if the deployment credential should be assigned Contribuor permissions on the subscription +#deployer_assign_subscription_permissions=true + +# use_private_endpoint is a boolean flag controlling if the keyvaults and storage accounts have private endpoints +# use_private_endpoint=false + +# use_service_endpoint is a boolean flag controlling service_endpoints are used +use_service_endpoint = true + +# auto_configure_deployer is a boolean flag controlling if the automation should try to configure the deployer automatically +# set to false if outbound internet on the deployer is not available +auto_configure_deployer = true + +# Boolean value indicating if firewall should be enabled for key vaults and storage +enable_firewall_for_keyvaults_and_storage = false + +# List of subnet IDs to add to storage account and key vault firewalls" +#subnets_to_add_to_firewall_for_keyvaults_and_storage=[""] diff --git a/.cfg_template/library.tfvars b/.cfg_template/library.tfvars new file mode 100644 index 0000000..829abd2 --- /dev/null +++ b/.cfg_template/library.tfvars @@ -0,0 +1,11 @@ +# The environment value is a mandatory field, it is used for partitioning the environments, for example (PROD and NP) +environment="@@ENV@@" + +# The location valus is a mandatory field, it is used to control where the resources are deployed +location="@@REGION@@" + +# Defines the DNS suffix for the resources +dns_label = "azure.sapcontoso.com" + +# use_private_endpoint defines that the storage accounts and key vaults have private endpoints enabled +use_private_endpoint = false diff --git a/.github/ISSUE_TEMPLATE/create_environment.yaml b/.github/ISSUE_TEMPLATE/create_environment.yaml new file mode 100644 index 0000000..c6dc45d --- /dev/null +++ b/.github/ISSUE_TEMPLATE/create_environment.yaml @@ -0,0 +1,39 @@ +name: Create Environment +description: Use this template to create a new environment. +title: Create Environment +labels: + - "create-environment" +body: + - type: markdown + attributes: + value: | + These steps will guide you through the process of creating a new environment. This will create a new environment for this repository to which you can connect your Azure subscription. + + More information about the naming convention can be found [here](https://learn.microsoft.com/en-us/azure/sap/automation/naming). + + - type: input + id: environment + attributes: + label: '​Environment​' # U+200B - Zero Width Space; to make sure the UI stays clean + description: 'The name of the environment you want to create. E.g. Dev, Test, Prod. Max five characters.' + placeholder: Dev + validations: + required: true + + - type: input + id: region_map + attributes: + label: '​Region​' # U+200B - Zero Width Space; to make sure the UI stays clean + description: 'Azure region to deploy the environment to. Use the short name, e.g. `westeurope`.' + placeholder: westeurope + validations: + required: true + + - type: input + id: vnet_name + attributes: + label: '​Deployer Vnet​' # U+200B - Zero Width Space; to make sure the UI stays clean + description: 'Virtual network in which the deployer should be deployed. Max 7 characters.' + placeholder: DEP01 + validations: + required: true diff --git a/.github/workflows/create-environment.tpl b/.github/workflows/create-environment.tpl new file mode 100644 index 0000000..9594678 --- /dev/null +++ b/.github/workflows/create-environment.tpl @@ -0,0 +1 @@ +No that you have finished setting a GitHub App and connected a Azure subscription to this repository, we can start creating an environment diff --git a/.github/workflows/create-environment.yaml b/.github/workflows/create-environment.yaml new file mode 100644 index 0000000..439e0df --- /dev/null +++ b/.github/workflows/create-environment.yaml @@ -0,0 +1,123 @@ +on: + issues: + types: [ opened, closed ] + +permissions: + issues: write + pull-requests: write + contents: read + actions: write + +jobs: + opened: + name: Create environment + runs-on: ubuntu-latest + container: + image: ghcr.io/xpiritbv/azure-sap-automation:github-workflow + ### if: contains(github.event.issue.labels.*.name, 'create-environment') && github.event.action == 'opened' + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Get app token + id: get_workflow_token + uses: peter-murray/workflow-application-token-action@v3 + with: + application_id: ${{ secrets.APPLICATION_ID }} + application_private_key: ${{ secrets.APPLICATION_PRIVATE_KEY }} + organization: ${{ github.repository_owner }} + + - name: 'Validate Azure Credentials' + run: | + #!/usr/bin/env bash + + set -euo pipefail + + function missing_secret { + azure_link_issue=$(gh issue list --json 'number' | jq '.[].number' -r | grep link-azure) + gh issue reopen ${azure_link_issue} + gh issue comment ${azure_link_issue} -m "To continue, we need to have Azure credentials set.\n\nPlease set them and try again." + exit 1 + } + + if [ -z "${{ secrets.AZURE_CLIENT_ID }}" || -z "${{ secrets.AZURE_CLIENT_SECRET }}" || -z "${{ secrets.AZURE_TENANT_ID }}" || -z "${{ secrets.AZURE_SUBSCRIPTION_ID }}" ]; then + missing_secret + fi + + az login --service-principal \ + --username ${{ secrets.AZURE_CLIENT_ID }} \ + --password=${{ secrets.AZURE_CLIENT_SECRET }} \ + --tenant ${{ secrets.AZURE_TENANT_ID }} \ + --output none + + if [ $? -ne 0 ]; then + missing_secret + fi + + az account set --subscription ${{ secrets.AZURE_SUBSCRIPTION_ID }} + + if [ $? -ne 0 ]; then + missing_secret + fi + + - name: Run Issue form parser + id: parse + uses: peter-murray/issue-forms-body-parser@v4 + with: + issue_id: ${{ github.event.issue.number }} + separator: '###' + label_marker_start: '​' # U+200B - Zero Width Space; to make sure the UI stays clean + label_marker_end: '​' # U+200B + + - name: 'Create GitHub Environment' + run: | + #!/usr/bin/env bash + + set -euo pipefail + + environment=$(echo "${{ steps.parse.outputs.payload }}" | jq -r '."Environment"') + region=$(echo "${{ steps.parse.outputs.payload }}" | jq -r '."Region"') + deployer_vnet=$(echo "${{ steps.parse.outputs.payload }}" | jq -r '."Deployer Vnet"') + + region_map=$(pushd /source/deploy/terraform/terraform-units/modules/sap_namegenerator; echo var.region_mapping.${region} | terraform console; popd) + region_display_name=$(az account list-locations -o json| jq --arg REGION $region '.[] | select(.name==$REGION) | .displayName' -r) + + deployer_name=${environment}-${region_map}-${deployer_vnet}-INFRASTRUCTURE + library_name=${environment}-${region_map}-SAP_LIBRARY + + gh auth login --with-token ${{ steps.get_workflow_token.outputs.token }} + + # make sure the environment does not exist + _=$(gh api \ + -H "Accept: application/vnd.github+json" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + /repos/xpiritbv/azure-sap-automation-deployer/environments/${environment}) + + if [ $? -eq 0 ]; then + echo "Environment already exists" + exit 1 + fi + + gh api -X PUT \ + -H "Accept: application/vnd.github+json" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + /repos/xpiritbv/azure-sap-automation-deployer/environments/${environment} + + mkdir -p ${{ github.workspace }}/WORKSPACES/DEPLOYER/${deployer_name^^} + mkdir -p ${{ github.workspace }}/WORKSPACES/LIBRARY/${library_name^^} + + cat .cfg_template/deployer.tfvars \ + | sed "s|@@ENV@@|${environment}|g" \ + | sed "s|@@REGION@@|${region}|g" \ + | sed "s|@@VNET@@|${deployer_vnet}|g" \ + | sed "s|@@USE_WEBAPP@@|${use_webapp}|g" \ + | sed "s|@@REGION_DISPLAY_NAME@@|${region_display_name}|g" \ + > ${{ github.workspace }}/WORKSPACES/DEPLOYER/${deployer_name^^}/${deployer_name^^}.tfvars + + cat .cfg_template/library.tfvars \ + | sed "s|@@ENV@@|${environment}|g" \ + | sed "s|@@REGION@@|${region}|g" \ + > ${{ github.workspace }}/WORKSPACES/LIBRARY/${library_name^^}/${library_name^^}.tfvars + + git add ${{ github.workspace }}/WORKSPACES + git commit -m "Add configuration for ${environment} in ${region}"