Merge pull request #98 from Azure/users/joselcaguilar/tfparity

TF Parity with bicep AKS Baseline
This commit is contained in:
Bahram Rushenas 2022-10-16 01:32:06 -07:00 коммит произвёл GitHub
Родитель 5ef840e236 f53c01220e
Коммит e9dbc5e856
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
32 изменённых файлов: 794 добавлений и 267 удалений

217
.github/workflows/IaC-terraform-AKS.yml поставляемый
Просмотреть файл

@ -1,16 +1,52 @@
name: 'IaC Deploy Terraform based AKS Cluster'
name: "IaC Deploy Terraform based AKS Cluster"
on:
workflow_dispatch:
inputs:
ENVIRONMENT:
description: 'A GitHub Environment to pull action secrets from'
description: "A GitHub Environment to pull action secrets from"
required: true
type: environment
REGION:
description: 'The Azure region to deploy to'
description: "The Azure region to deploy to"
type: string
required: true
default: eastus
TF_BACKEND_STORAGE_ACCOUNT:
description: "The Azure Storage Account where TF backend will be stored (must be unique). Skip this param if you want to use a TF local backend"
type: string
required: false
default: ""
clusterAdminAADGroupObjectId:
description: 'K8S Admin Azure AAD Group ObjectID'
required: false
type: string
default: ""
clusterUserAADGroupObjectId:
description: 'K8S Reader Azure AAD Group ObjectID'
required: false
type: string
default: ""
DEPLOY_PLAN_ONLY:
description: "Execute Terraform plan only"
type: boolean
required: false
default: false
DEPLOY:
description: "Execute Terraform apply"
type: boolean
required: false
default: true
DESTROY_PLAN_ONLY:
description: "Execute Terraform plan -destroy only"
type: boolean
required: false
default: false
DESTROY:
description: "Execute Terraform destroy"
type: boolean
required: false
default: false
env:
AZURE_CREDENTIALS: '{"clientId":"${{ secrets.AZURE_CLIENT_ID }}", "clientSecret":"${{ secrets.AZURE_CLIENT_SECRET }}", "subscriptionId":"${{ secrets.AZURE_SUBSCRIPTION_ID }}", "tenantId":"${{ secrets.AZURE_TENANT_ID }}"}'
@ -20,7 +56,10 @@ env:
ARM_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
ARM_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }}
ARM_PARTNER_ID: "451dc593-a3a3-4d41-91e7-3aadf93e1a78"
ENVIRONMENT: "1${{ github.run_id }}"
ENVIRONMENT: "${{ github.repository }}/${{ github.ref_name }}-${{ github.event.inputs.ENVIRONMENT }}"
TF_BACKEND_RSG: "rg-enterprise-tf-dependencies"
TF_VERSION: "1.3.2"
AZ_CLI_VERSION: "2.41.0" # Updated thanks to the WAF Policy, reference https://github.com/Azure/azure-cli/issues/24029 added just in case new issues arise
permissions:
id-token: write
@ -39,62 +78,142 @@ jobs:
- name: "Parameter Check"
run: |
echo "Environment : ${{ github.event.inputs.ENVIRONMENT }}"
echo "Environment tag : ${{ env.ENVIRONMENT }}"
echo "REGION : ${{ github.event.inputs.REGION }}"
echo "TF_BACKEND_STORAGE_ACCOUNT : ${{ github.event.inputs.TF_BACKEND_STORAGE_ACCOUNT }}"
echo "DEPLOY_PLAN_ONLY : ${{ github.event.inputs.DEPLOY_PLAN_ONLY }}"
echo "DEPLOY : ${{ github.event.inputs.DEPLOY }}"
echo "DESTROY_PLAN_ONLY : ${{ github.event.inputs.DESTROY_PLAN_ONLY }}"
echo "DESTROY : ${{ github.event.inputs.DESTROY }}"
# OIDC auth is not supported until TF AzureRM 3.7.0 onwards
- name: Azure Login
uses: Azure/login@v1.4.3
uses: Azure/login@v1.4.6
with:
creds: ${{ env.AZURE_CREDENTIALS }}
# client-id: ${{ secrets.AZURE_CLIENT_ID }}
# tenant-id: ${{ secrets.AZURE_TENANT_ID }}
# subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
- uses: hashicorp/setup-terraform@v1
- name: Create Resource Group and Storage Account for TF State
if: ${{ github.event.inputs.TF_BACKEND_STORAGE_ACCOUNT != '' && (github.event.inputs.DEPLOY_PLAN_ONLY == 'true' || github.event.inputs.DEPLOY == 'true') }}
uses: azure/CLI@v1
with:
terraform_version: 1.1.6
terraform_wrapper: false
# https://stackoverflow.com/questions/65170927/terraform-output-value-failed-formatted-by-jq-in-github-actions
inlineScript: |
az group create -l ${{ github.event.inputs.REGION }} -n ${{ env.TF_BACKEND_RSG }}
az storage account create -n ${{ github.event.inputs.TF_BACKEND_STORAGE_ACCOUNT }} -g ${{ env.TF_BACKEND_RSG }} -l ${{ github.event.inputs.REGION }} --sku Standard_LRS --https-only $true --min-tls-version TLS1_2
az storage container create -n tfstate --account-name ${{ github.event.inputs.TF_BACKEND_STORAGE_ACCOUNT }}
- name: Deploy Plan Standalone
if: ${{ github.event.inputs.DEPLOY_PLAN_ONLY == 'true' || github.event.inputs.DEPLOY == 'true' }}
uses: azure/CLI@v1
with:
azcliversion: ${{ env.AZ_CLI_VERSION }}
inlineScript: |
cd IaC/terraform
ls -lta
wget -nc https://releases.hashicorp.com/terraform/${{ env.TF_VERSION }}/terraform_${{ env.TF_VERSION }}_linux_amd64.zip
unzip -o terraform_${{ env.TF_VERSION }}_linux_amd64.zip
rm terraform_${{ env.TF_VERSION }}_linux_amd64.zip
git clone https://github.com/Azure/caf-terraform-landingzones.git landingzone
parameter_files=$(find configuration -not -path "*launchpad*" | grep .tfvars | sed 's/.*/-var-file &/' | xargs)
echo "parameter_files: ${parameter_files}"
if [ -n ${{ github.event.inputs.TF_BACKEND_STORAGE_ACCOUNT }} ]
then
./terraform init -upgrade -backend-config=storage_account_name="${{ github.event.inputs.TF_BACKEND_STORAGE_ACCOUNT }}" -backend-config=container_name="tfstate" -backend-config=key="aks-baseline.tfstate" -backend-config=resource_group_name="${{ env.TF_BACKEND_RSG }}"
else
./terraform init -upgrade
fi
eval ./terraform plan ${parameter_files} -var 'tags={repo_environment=\"$ENVIRONMENT\"}' -var 'regions=[\"${{ github.event.inputs.REGION }}\"]' -var 'clusterAdminAADGroupsObjectIds=[\"${{ github.event.inputs.clusterAdminAADGroupObjectId }}\"]' -var 'clusterUserAADGroupsObjectIds=[\"${{ github.event.inputs.clusterUserAADGroupObjectId }}\"]' -out tfdeployplan
- name: Deploy Standalone
if: contains(github.event.comment.body, '/deploy-all') || contains(github.event.comment.body, '/deploy-launchpad') || github.event_name != 'issue_comment'
run: |
pwd
cd IaC/terraform
git clone https://github.com/Azure/caf-terraform-landingzones.git landingzone
parameter_files=$(find configuration -not -path "*launchpad*" | grep .tfvars | sed 's/.*/-var-file &/' | xargs)
if: ${{ github.event.inputs.DEPLOY == 'true' }}
uses: azure/CLI@v1
with:
azcliversion: ${{ env.AZ_CLI_VERSION }}
inlineScript: |
cd IaC/terraform
ls -lta
terraform init -upgrade
eval terraform apply ${parameter_files} -var tags='{testing_job_id='"$ENVIRONMENT"'}' -auto-approve
eval ./terraform apply -parallelism=30 -auto-approve tfdeployplan
- name: Destroy Plan Standalone
if: ${{ github.event.inputs.DESTROY_PLAN_ONLY == 'true' || github.event.inputs.DESTROY == 'true' }}
uses: azure/CLI@v1
with:
azcliversion: ${{ env.AZ_CLI_VERSION }}
inlineScript: |
cd IaC/terraform
ls -lta
if [ ${{ github.event.inputs.DEPLOY_PLAN_ONLY }} == 'false' ] && [ ${{ github.event.inputs.DEPLOY }} == 'false' ]
then
wget -nc https://releases.hashicorp.com/terraform/${{ env.TF_VERSION }}/terraform_${{ env.TF_VERSION }}_linux_amd64.zip
unzip -o terraform_${{ env.TF_VERSION }}_linux_amd64.zip
rm terraform_${{ env.TF_VERSION }}_linux_amd64.zip
if [ -n ${{ github.event.inputs.TF_BACKEND_STORAGE_ACCOUNT }} ]
then
./terraform init -upgrade -backend-config=storage_account_name="${{ github.event.inputs.TF_BACKEND_STORAGE_ACCOUNT }}" -backend-config=container_name="tfstate" -backend-config=key="aks-baseline.tfstate" -backend-config=resource_group_name="${{ env.TF_BACKEND_RSG }}"
else
./terraform init -upgrade
fi
fi
if [ ${{ github.event.inputs.DESTROY_PLAN_ONLY }} == 'false' ]
then
tf_state_resources=`./terraform state list | grep 'module.flux_addon' || true`
if [ ${#tf_state_resources} -gt 0 ]
then
echo "Destroying Flux Addon from state as flux provider has issues with destroy"
./terraform state rm 'module.flux_addon'
fi
fi
parameter_files=$(find configuration -not -path "*launchpad*" | grep .tfvars | sed 's/.*/-var-file &/' | xargs)
echo "parameter_files: ${parameter_files}"
eval ./terraform plan ${parameter_files} -var 'tags={repo_environment=\"$ENVIRONMENT\"}' -var 'regions=[\"${{ github.event.inputs.REGION }}\"]' -var 'clusterAdminAADGroupsObjectIds=[\"${{ github.event.inputs.clusterAdminAADGroupObjectId }}\"]' -var 'clusterUserAADGroupsObjectIds=[\"${{ github.event.inputs.clusterUserAADGroupObjectId }}\"]' -destroy -out tfdestroyplan
- name: Diagnostics purge
if: ${{ github.event.inputs.DESTROY == 'true' }}
run: |
echo RepoEnvironment $ENVIRONMENT
resource_groups_array=(`az group list --tag repo_environment='${{ env.ENVIRONMENT }}' --query '[].name' -o json | jq -r '.[]'`)
echo Resource Groups tagged : ${resource_groups_array[@]}
resource_ids_array=()
for i in "${resource_groups_array[@]}"; do resource_ids_array+=(`az resource list -g $i -o json --query '[].id' | jq -r '.[]'`); done
diagnostic_names=()
diagnostic_parent_ids=()
for i in "${resource_ids_array[@]}"
do
diagnostic_query=`az monitor diagnostic-settings list --resource $i --query 'value[]' 2>nul || true`
if [ ${#diagnostic_query} -gt 2 ]; then
diagnostic_names+=(`echo $diagnostic_query | jq -r '.[].name'`)
diagnostic_parent_ids+=(`echo $diagnostic_query | jq -r '.[].id' | grep -oP '^.*?(?=\/providers\/microsoft.insights)'`)
fi
done
for (( i=0; i<${#diagnostic_names[@]}; i++ ))
do
echo "Purging diagnostic-settings: ${diagnostic_names[$i]}" && \
$(az monitor diagnostic-settings delete --resource ${diagnostic_parent_ids[$i]} --name ${diagnostic_names[$i]})
done
- name: Destroy Standalone
if: contains(github.event.comment.body, '/deploy-all') || contains(github.event.comment.body, '/deploy-launchpad') || github.event_name != 'issue_comment'
run: |
ls -lta
pwd
cd IaC/terraform/
parameter_files=$(find configuration -not -path "*launchpad*" | grep .tfvars | sed 's/.*/-var-file &/' | xargs)
# remove flux from state as flux provider has issues with destroy
terraform state rm 'module.flux_addon'
eval terraform destroy ${parameter_files} -var tags='{testing_job_id='"$ENVIRONMENT"'}' -auto-approve
purge:
name: purge
runs-on: ubuntu-latest
environment: terraform
if: ${{ failure() || cancelled() }}
needs: [deploy-standalone]
steps:
- name: Login azure
run: |
az login --service-principal -u '${{ env.ARM_CLIENT_ID }}' -p '${{ env.ARM_CLIENT_SECRET }}' --tenant '${{ env.ARM_TENANT_ID }}'
az account set -s ${{ env.ARM_SUBSCRIPTION_ID }}
if: ${{ github.event.inputs.DESTROY == 'true' }}
uses: azure/CLI@v1
with:
azcliversion: ${{ env.AZ_CLI_VERSION }}
inlineScript: |
cd IaC/terraform
ls -lta
eval ./terraform apply -parallelism=30 -auto-approve tfdestroyplan
- name: Complete purge
if: ${{ github.event.inputs.DESTROY == 'true' }}
run: |
echo RunId $ENVIRONMENT
for i in `az monitor diagnostic-settings subscription list -o tsv --query "value[?contains(name, '$ENVIRONMENT' )].name"`; do echo "purging subscription diagnostic-settings: $i" && $(az monitor diagnostic-settings subscription delete --name $i --yes); done
for i in `az monitor log-profiles list -o tsv --query '[].name'`; do az monitor log-profiles delete --name $i; done
# for i in `az ad group list --query "[?contains(displayName, '$ENVIRONMENT')].objectId" -o tsv`; do echo "purging Azure AD group: $i" && $(az ad group delete --verbose --group $i || true); done
# for i in `az ad app list --query "[?contains(displayName, '$ENVIRONMENT')].appId" -o tsv`; do echo "purging Azure AD app: $i" && $(az ad app delete --verbose --id $i || true); done
for i in `az keyvault list-deleted --query "[?tags.testing_job_id=='$ENVIRONMENT'].name" -o tsv`; do az keyvault purge --name $i; done
for i in `az group list --query "[?tags.testing_job_id=='$ENVIRONMENT'].name" -o tsv`; do echo "purging resource group: $i" && $(az group delete -n $i -y --no-wait || true); done
for i in `az role assignment list --query "[?contains(roleDefinitionName, '$ENVIRONMENT')].roleDefinitionName" -o tsv`; do echo "purging role assignment: $i" && $(az role assignment delete --role $i || true); done
for i in `az role definition list --query "[?contains(roleName, '$ENVIRONMENT')].roleName" -o tsv`; do echo "purging custom role definition: $i" && $(az role definition delete --name $i || true); done
for i in `az keyvault list-deleted --query "[?properties.tags.repo_environment=='$ENVIRONMENT'].name" -o tsv`; do az keyvault purge --name $i; done

Просмотреть файл

@ -1,4 +1,4 @@
# terraform (still in development but you can still try it out)
# Terraform
This folder contains the code to build the [AKS Baseline reference implementation](https://learn.microsoft.com/azure/architecture/reference-architectures/containers/aks/secure-baseline-aks) using [CAF Terraform Landing zone framework composition](https://github.com/aztfmod/terraform-azurerm-caf).
@ -6,26 +6,26 @@ The following components will be deployed as part of this automation:
![aks_enterprise_scale_lz](../../media/aks_enterprise_scale_lz2.png)
| Components | Config files | Description|
|-----------------------------------------------------------|------------------------------------------------------------|------------------------------------------------------------|
| Global Settings |[global_settings.tfvars](./configuration/global_settings.tfvars) | Primary Region setting. Changing this will redeploy the whole stack to another Region|
| Resource Groups | [resource_groups.tfvars](./configuration/resource_groups.tfvars)| Resource groups configs |
| Azure Kubernetes Service | [aks.tfvars](./configuration/aks.tfvars) | AKS addons, version, nodepool configs |
||<p align="center">**Identity & Access Management**</p>||
| Identity & Access Management | [iam_managed_identities.tfvars](./configuration/iam/iam_managed_identities.tfvars) <br /> [iam_role_mappings.tfvars](./configuration/iam/iam_role_mappings.tfvars)| AAD admin group, User Managed Identities & Role Assignments |
||<p align="center">**Gateway**</p>||
| Application Gateway | [agw.tfvars](./configuration/agw/agw.tfvars) <br /> [agw_application.tfvars](./configuration/agw/agw_application.tfvars) <br />| Application Gateway WAF v2 Configs with aspnetapp workload settings |
| App Service Domains | [domain.tfvars](./configuration/agw/domain.tfvars) | Public domain to be used in Application Gateway |
||<p align="center">**Networking**</p>||
| Virtual networks | [networking.tfvars](./configuration/networking/networking.tfvars) <br /> [peerings.tfvars](./configuration/networking/peerings.tfvars) <br /> [nsg.tfvars](./configuration/networking/nsg.tfvars) <br /> [ip_groups.tfvars](./configuration/networking/ip_groups.tfvars)| CIDRs, Subnets, NSGs & peerings config for Azure Firewall Hub & AKS Spoke |
| Private DNS Zone | [private_dns.tfvars](./configuration/networking/private_dns.tfvars) | Private DNS zone for AKS ingress; A record to Load Balancer IP |
| Azure Firewall | [firewalls.tfvars](./configuration/networking/firewalls.tfvars) <br /> [firewall_application_rule_collection_definition.tfvars](./configuration/networking/firewall_application_rule_collection_definition.tfvars) <br /> [firewall_network_rule_collection_definition.tfvars](./configuration/networking/firewall_network_rule_collection_definition.tfvars) <br /> [route_tables.tfvars](./configuration/networking/route_tables.tfvars) | Azure Firewall for restricting AKS egress traffic|
| Public IPs | [public_ips.tfvars](./configuration/networking/public_ips.tfvars) | Public IPs for Application Gateway, Azure Firewall & Azure Bastion Host |
||<p align="center">**Security & Monitoring**</p>||
| Azure Key Vault| [keyvaults.tfvars](./configuration/keyvault/keyvaults.tfvars) <br /> [certificate_requests.tfvars](./configuration/keyvault/certificate_requests.tfvars) | Key Vault to store Self signed certificate for AKS ingress & Bastion SSH key |
| Azure Monitor | [diagnostics.tfvars](./configuration/monitor/diagnostics.tfvars) <br /> [log_analytics.tfvars](./configuration/monitor/log_analytics.tfvars) | Diagnostics settings, Log Analytics Workspace for AKS logs & Prometheus metrics |
||<p align="center">**Bastion**</p>||
| Azure Bastion (OPTIONAL) | [bastion.tfvars](./configuration/bastion/bastion.ignore) | Azure Bastion Host & Windows VM to view aspnetsample website internally. |
| Components | Config files | Description |
| ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------- |
| Global Settings | [global_settings.tfvars](./configuration/global_settings.tfvars) | Primary Region setting. Changing this will redeploy the whole stack to another Region |
| Resource Groups | [resource_groups.tfvars](./configuration/resource_groups.tfvars) | Resource groups configs |
| Azure Kubernetes Service | [aks.tfvars](./configuration/aks.tfvars) | AKS addons, version, nodepool configs |
| | <p align="center">**Identity & Access Management**</p> | |
| Identity & Access Management | [iam_managed_identities.tfvars](./configuration/iam/iam_managed_identities.tfvars) <br /> [iam_role_mappings.tfvars](./configuration/iam/iam_role_mappings.tfvars) | AAD admin group, User Managed Identities & Role Assignments |
| | <p align="center">**Gateway**</p> | |
| Application Gateway | [agw.tfvars](./configuration/agw/agw.tfvars) <br /> [agw_application.tfvars](./configuration/agw/agw_application.tfvars) <br /> [waf_policies.tfvars](./configuration/agw/waf_policies.tfvars) <br /> | Application Gateway WAF v2 Configs and Policies with aspnetapp workload settings |
| App Service Domains | [domain.tfvars](./configuration/agw/domain.tfvars) | Public domain to be used in Application Gateway |
| | <p align="center">**Networking**</p> | |
| Virtual networks | [networking.tfvars](./configuration/networking/networking.tfvars) <br /> [peerings.tfvars](./configuration/networking/peerings.tfvars) <br /> [nsg.tfvars](./configuration/networking/nsg.tfvars) <br /> [ip_groups.tfvars](./configuration/networking/ip_groups.tfvars) | CIDRs, Subnets, NSGs & peerings config for Azure Firewall Hub & AKS Spoke |
| Private DNS Zone | [private_dns.tfvars](./configuration/networking/private_dns.tfvars) | Private DNS zone for AKS ingress; A record to Load Balancer IP |
| Azure Firewall | [firewalls.tfvars](./configuration/networking/firewalls.tfvars) <br /> [firewall_application_rule_collection_definition.tfvars](./configuration/networking/firewall_application_rule_collection_definition.tfvars) <br /> [firewall_network_rule_collection_definition.tfvars](./configuration/networking/firewall_network_rule_collection_definition.tfvars) <br /> [route_tables.tfvars](./configuration/networking/route_tables.tfvars) | Azure Firewall for restricting AKS egress traffic |
| Public IPs | [public_ips.tfvars](./configuration/networking/public_ips.tfvars) | Public IPs for Application Gateway, Azure Firewall & Azure Bastion Host |
| | <p align="center">**Security & Monitoring**</p> | |
| Azure Key Vault | [keyvaults.tfvars](./configuration/keyvault/keyvaults.tfvars) <br /> [certificate_requests.tfvars](./configuration/keyvault/certificate_requests.tfvars) | Key Vault to store Self signed certificate for AKS ingress & Bastion SSH key |
| Azure Monitor | [diagnostics.tfvars](./configuration/monitor/diagnostics.tfvars) <br /> [log_analytics.tfvars](./configuration/monitor/log_analytics.tfvars) | Diagnostics settings, Log Analytics Workspace for AKS logs & Prometheus metrics |
| | <p align="center">**Bastion**</p> | |
| Azure Bastion (OPTIONAL) | [bastion.tfvars](./configuration/bastion/bastion.ignore) | Azure Bastion Host & Windows VM to view aspnetsample website internally. |
<br />
@ -46,25 +46,34 @@ To customize the sample terraform templates provided based on your specific need
## Customize the GitHub action workflows
To customize the sample GitHub pipeline provided based on your specific needs, follow the instructions below:
1. Create your workflow [GitHub Environment](https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment?msclkid=62181fb1ab7511ec9be085113913a757) to store the following secrets:
1. Create your workflow [GitHub Environment](https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment) to store the following secrets:
| Secret | Description |Sample|
|--------|-------------|------|
|ENVIRONMENT| Name of the environment where you are deploying the Azure resources|non-prod|
|ARM_CLIENT_ID| Service Principal which will be used to provision resources||
|ARM_CLIENT_SECRET| Service Principal secret||
|ARM_SUBSCRIPTION_ID| Azure subscription id||
|ARM_TENANT_ID| Azure tenant id||
|FLUX_TOKEN| [GitHub Personal Access Token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token) for Flux V2||
| Secret | Description | Sample |
| --------------------- | ----------------------------------------------------------- | ------ |
| AZURE_CLIENT_ID | Service Principal which will be used to provision resources | |
| AZURE_CLIENT_SECRET | Service Principal secret | |
| AZURE_SUBSCRIPTION_ID | Azure subscription id | |
| AZURE_TENANT_ID | Azure tenant id | |
Note: do not modify the names of these secrets in the workflow yaml file as they are expected in terraform to be named as shown above.
Also instead of using a Service Principal and storing the secret in the GitHub Cloud, you should setup [Workload Identity federation with OpenID Connect](https://learn.microsoft.com/azure/developer/github/connect-from-azure?tabs=azure-portal%2Cwindows#use-the-azure-login-action-with-openid-connect). Follow [these steps](../oidc-federated-credentials.md) to set it up.
> Note: Do not modify the names of these secrets in the workflow yaml file as they are expected in terraform to be named as shown above.
Also instead of using a Service Principal and storing the secret in the GitHub Cloud, once AzureRM Provider is updated to 3.7.0+ you should setup [Workload Identity federation with OpenID Connect](https://learn.microsoft.com/azure/developer/github/connect-from-azure?tabs=azure-portal%2Cwindows#use-the-azure-login-action-with-openid-connect). Follow [these steps](../oidc-federated-credentials.md) to set it up with [Terraform Azure Provider Auth](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/guides/service_principal_oidc).
2. Update the workflow [IaC-terraform-AKS.yml](../../.github/workflows/IaC-terraform-AKS.yml) with the name of the Environment you created in the previous step. The default Environment name is "Terraform". Commit the changes to your remote GitHub branch so that you can run the workflow.
Note that this sample workflow file deploys Azure resources respectively in the hub and spoke resource groups as specified in the [AKS Baseline Reference Implementation](https://github.com/mspnp/aks-baseline).
2. Provide the workflow [IaC-terraform-AKS.yml](../../.github/workflows/IaC-terraform-AKS.yml) inputs during the workflow run:
| Input | Description | Default value | Required |
| ---------------------------- | --------------------------------------------------------------------------------------------------------------------------------- | ------------- | ------------------ |
| ENVIRONMENT | A GitHub Environment which must be selected to pull action secrets from | | :white_check_mark: |
| REGION | The Azure region to deploy to | eastus | ❌ |
| TF_BACKEND_STORAGE_ACCOUNT | The Azure Storage Account where TF backend will be stored (must be unique). Skip this param if you want to use a TF local backend | "" | ❌ |
| DEPLOY_PLAN_ONLY | Execute Terraform plan only | false | ❌ |
| DEPLOY | Execute Terraform apply only | true | ❌ |
| DESTROY_PLAN_ONLY | Execute Terraform plan -destroy only | false | ❌ |
| DESTROY | Execute Terraform destroy | false | ❌ |
| clusterAdminAADGroupObjectId | K8S Admin Azure AAD Group ObjectID | "" | ❌ |
| clusterUserAADGroupObjectId | K8S User Azure AAD Group ObjectID | "" | ❌ |
> Note: This sample workflow file deploys Azure resources respectively in the hub and spoke resource groups as specified in the [AKS Baseline Reference Implementation](https://github.com/mspnp/aks-baseline).
## Kick-iff the GitHub action workflow
## Kick-off the GitHub action workflow
As the workflow trigger is set to "workflow_dispatch", you can manually start it by clicking on [Actions](https://github.com/Azure/aks-baseline-automation/actions) in this repo, find the workflow [IaC-terraform-AKS.yml](../../.github/workflows/IaC-terraform-AKS.yml), and run it by clicking on the "Run Workflow" drop down.
As the workflow runs, monitor its logs for any error.

Просмотреть файл

@ -1,17 +1,18 @@
terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "~> 2.88.1"
version = ">= 2.99.0"
}
kubernetes = {
source = "hashicorp/kubernetes"
version = "~> 2.0.2"
version = ">= 2.14.0"
}
kustomization = {
source = "kbst/kustomization"
version = "~> 0.5.0"
version = ">= 0.9.0"
}
}
required_version = ">= 0.13"
required_version = ">= 1.3.0"
}

Просмотреть файл

@ -18,6 +18,6 @@ provider "kustomization" {
# Get kubeconfig from AKS clusters
data "azurerm_kubernetes_cluster" "kubeconfig" {
name = var.aks_clusters[var.aks_cluster_key].cluster_name
resource_group_name = var.aks_clusters[var.aks_cluster_key].resource_group_name
name = var.caf_config.aks_clusters[var.aks_cluster_key].cluster_name
resource_group_name = var.caf_config.aks_clusters[var.aks_cluster_key].resource_group_name
}

Просмотреть файл

@ -1,7 +1,7 @@
variable "aks_cluster_key" {
description = "AKS cluster key to deploy AAD Pod identities CRDs objects. The key must be defined in the variable aks_clusters"
}
variable "aks_clusters" {
variable "caf_config" {
default = {}
}
variable "vnets" {

Просмотреть файл

@ -1,5 +1,5 @@
module "flux_addon" {
source = "github.com/Azure/caf-terraform-landingzones//caf_solution/add-ons/aks_secure_baseline_v2/flux"
source = "github.com/Azure/caf-terraform-landingzones/caf_solution/add-ons/aks_secure_baseline_v2/flux"
# source = "../../landingzone/caf_solution/add-ons/aks_secure_baseline_v2/flux"
for_each = var.flux_settings
setting = each.value

Просмотреть файл

@ -2,19 +2,16 @@ terraform {
required_providers {
kubernetes = {
source = "hashicorp/kubernetes"
version = ">= 2.0.2"
version = ">= 2.14.0"
}
kubectl = {
source = "gavinbunney/kubectl"
version = ">= 1.11.1"
version = ">= 1.14.0"
}
flux = {
source = "fluxcd/flux"
version = ">= 0.2.0"
version = ">= 0.19.0"
}
}
required_version = ">= 0.13"
required_version = ">= 1.3.0"
}

Просмотреть файл

@ -24,6 +24,6 @@ provider "kubernetes" {
# Get kubeconfig from AKS clusters
data "azurerm_kubernetes_cluster" "kubeconfig" {
name = var.aks_clusters[var.aks_cluster_key].cluster_name
resource_group_name = var.aks_clusters[var.aks_cluster_key].resource_group_name
name = var.caf_config.aks_clusters[var.aks_cluster_key].cluster_name
resource_group_name = var.caf_config.aks_clusters[var.aks_cluster_key].resource_group_name
}

Просмотреть файл

@ -1,7 +1,5 @@
variable "aks_clusters" {
variable "caf_config" {
default = {}
}
variable "aks_cluster_key" {}
variable "flux_settings" {}

Просмотреть файл

@ -13,6 +13,12 @@ azure_container_registries = {
}
# georeplication_region_keys = ["region2"]
network_rule_set = {
deny_public_access = {
default_action = "Deny"
}
}
private_endpoints = {
# Require enforce_private_link_endpoint_network_policies set to true on the subnet
spoke_aks_re1-aks_nodepool_system = {

Просмотреть файл

@ -1,4 +1,4 @@
application_gateways = {
application_gateway_platforms = {
agw1_az1 = {
resource_group_key = "aks_re1"
name = "appgateway-re1-001"
@ -6,6 +6,9 @@ application_gateways = {
subnet_key = "application_gateway"
sku_name = "WAF_v2"
sku_tier = "WAF_v2"
waf_policy = {
key = "wp1"
}
capacity = {
autoscale = {
minimum_scale_unit = 0
@ -13,7 +16,7 @@ application_gateways = {
}
}
zones = ["1"]
enable_http2 = true
enable_http2 = false
identity = {
managed_identity_keys = [
@ -25,15 +28,6 @@ application_gateways = {
public = {
name = "public"
public_ip_key = "agw_pip1_re1"
subnet_key = "application_gateway"
}
private = {
name = "private"
vnet_key = "vnet_aks_re1"
subnet_key = "application_gateway"
subnet_cidr_index = 0 # It is possible to have more than one cidr block per subnet
private_ip_offset = 4 # e.g. cidrhost(10.10.0.0/25,4) = 10.10.0.4 => AGW private IP address
private_ip_address_allocation = "Static"
}
}
@ -50,12 +44,52 @@ application_gateways = {
}
}
ssl_certs = {
sslagwcert = {
name = "sslagwcert1"
keyvault = {
certificate_name = "appgateway"
key = "secrets"
}
}
}
trusted_root_certificate = {
wildcard_ingress = {
name = "wildcard-ingress"
# data =
name = "wildcard-ingress"
keyvault_key = "secrets"
}
}
diagnostic_profiles = {
operations = {
name = "agw_logs"
definition_key = "azure_application_gateway"
destination_type = "log_analytics"
destination_key = "central_logs"
}
}
#default: wont be able to change after creation as this is required for agw tf resource
default = {
frontend_port_key = "80"
frontend_ip_configuration_key = "public"
backend_address_pool_name = "default-beap"
http_setting_name = "default-be-htst"
cookie_based_affinity = "Disabled"
request_timeout = "60"
ssl_cert_key = "sslagwcert"
listener_name = "default-httplstn"
request_routing_rule_name = "default-rqrt"
rule_type = "Basic"
}
listener_ssl_policy = {
default = {
policy_type = "Predefined"
policy_name = "AppGwSslPolicy20170401S"
min_protocol_version = "TLSv1_2"
}
}
}
}

Просмотреть файл

@ -1,53 +1,62 @@
application_gateway_applications = {
application_gateway_applications_v1 = {
aspnetapp_az1_agw1 = {
name = "aspnetapp"
application_gateway_key = "agw1_az1"
listeners = {
http_listeners = {
public_ssl = {
name = "public-443"
front_end_ip_configuration_key = "public"
front_end_port_key = "443"
# host_name = "www.y4plq60ubbbiop9w1dh36tlgfpxqctfj.com"
dns_zone = {
key = "dns_zone1"
record_type = "a"
record_key = "agw"
}
request_routing_rule_key = "default"
# key_vault_secret_id = ""
# keyvault_certificate = {
# certificate_key = "aspnetapp.cafdemo.com"
# }
keyvault_certificate_request = {
key = "appgateway"
}
ssl_cert_key = "sslagwcert"
}
}
request_routing_rules = {
default = {
rule_type = "Basic"
name = "default_request_routing_rule_1"
rule_type = "Basic"
http_listener_key = "public_ssl"
backend_pool_key = "backend_pool_1"
http_settings_key = "http_setting_1"
priority = 100
}
}
backend_http_setting = {
port = 443
protocol = "Https"
pick_host_name_from_backend_address = true
# trusted_root_certificate_names = ["wildcard-ingress"]
trusted_root_certificate_names = ["wildcard-ingress"]
http_settings = {
http_setting_1 = {
name = "aks_http_setting_1"
front_end_port_key = "443"
root_certs = "wildcard-ingress"
host_name_from_backend_pool = true
timeout = 20
cookie_based_affinity = "Disabled"
enable_probe = true
probe_key = "probe_1"
}
}
probes = {
probe_1 = {
name = "probe-fqdn-backend-aks"
protocol = "Https"
path = "/"
interval = 30
timeout = 30
threshold = 3
min_servers = 0
host_name_from_http_settings = true
}
}
backend_pool = {
fqdns = [
"bu0001a0008-00.aks-ingress.contoso.com"
]
backend_pools = {
backend_pool_1 = {
name = "aks-pool-1"
fqdns = [
"bu0001a0008-00.aks-ingress.contoso.com"
]
}
}
}

Просмотреть файл

@ -0,0 +1,25 @@
application_gateway_waf_policies = {
wp1 = {
name = "waf-akscluster-re1-001"
resource_group_key = "aks_re1"
policy_settings = {
enabled = true
mode = "Prevention"
file_upload_limit_in_mb = 10
}
managed_rules = {
managed_rule_set = {
mrs1 = {
type = "OWASP"
version = "3.2"
}
mrs2 = {
type = "Microsoft_BotManagerRuleSet"
version = "0.1"
}
}
}
}
}

Просмотреть файл

@ -18,8 +18,8 @@ aks_clusters = {
}
# kubernetes_version = "1.20.5"
vnet_key = "vnet_aks_re1"
kubernetes_version = "1.23.8"
vnet_key = "vnet_aks_re1"
# network plugin and network policy should be "azure" (recommended by Secure AKS baseline)
network_profile = {
@ -36,11 +36,6 @@ aks_clusters = {
azure_active_directory = {
managed = true
azure_rbac_enabled = true
# admin_group_object_names = ["aks-cluster-re1-admins"]
# admin_group_object_ids = ["50f1138f-1d8c-4eab-b643-e3a02820f244"]
# azuread_groups = {
# keys = ["aks_cluster_re1_admins"]
# }
}
}
@ -54,10 +49,10 @@ aks_clusters = {
azure_policy = {
enabled = true
}
# ingress_application_gateway = {
# enabled = true
# key = "agw1_az1"
# }
ingress_application_gateway = {
enabled = true
key = "agw1_az1"
}
}

Просмотреть файл

@ -1,7 +1,7 @@
global_settings = {
default_region = "region1"
regions = {
region1 = "southeastasia" # You can adjust the Azure Region you want to use to deploy AKS and the related services
region1 = "westeurope" # You can adjust the Azure Region you want to use to deploy AKS and the related services
# region2 = "eastasia" # Optional - Add additional regions
}
passthrough = true

Просмотреть файл

@ -7,25 +7,39 @@ role_mapping = {
built_in_role_mapping = {
keyvaults = {
secrets = {
"Contributor" = {
"Key Vault Reader" = {
managed_identities = {
keys = ["ingress"]
}
} // "Contributor"
} // logged_in_subscription
} // subscriptions
aks_clusters = {
cluster_re1 = {
"Azure Kubernetes Service RBAC Cluster Admin" = {
# azuread_groups = {
# keys = ["aks_admins"]
# }
logged_in = {
keys = ["user"]
keys = ["ingress", "apgw_keyvault_secrets"]
}
}
}
}
# AKS Cluster roles provided using ../../locals.tf
# aks_clusters = {
# cluster_re1 = {
# "Azure Kubernetes Service RBAC Cluster Admin" = {
# # azuread_groups = {
# # keys = ["aks_cluster_re1_admins"]
# # }
# # logged_in = {
# # keys = ["user"]
# # }
# }
# "Azure Kubernetes Service Cluster User Role" = {
# # azuread_groups = {
# # keys = ["aks_cluster_re1_admins, aks_cluster_re1_users"]
# # }
# # logged_in = {
# # keys = ["user"]
# # }
# }
# "Azure Kubernetes Service RBAC Reader" = {
# # azuread_groups = {
# # keys = ["aks_cluster_re1_users"]
# # }
# }
# }
# }
azure_container_registries = {
acr1 = {
"AcrPull" = {
@ -35,6 +49,15 @@ role_mapping = {
}
}
}
resource_groups = {
aks_re1 = {
"Monitoring Metrics Publisher" = {
aks_clusters = {
keys = ["cluster_re1"]
}
}
}
}
} // built_in_role_mapping
} // role_mapping

Просмотреть файл

@ -3,11 +3,12 @@ keyvaults = {
# This keyvault is used to store the complex password created for the AKS breakglass admin user
secrets = {
name = "secretsvault_re1"
resource_group_key = "aks_re1"
region = "region1"
sku_name = "premium"
soft_delete_enabled = true
name = "secretsvaultre001"
resource_group_key = "aks_re1"
region = "region1"
sku_name = "premium"
enabled_for_template_deployment = true
enable_rbac_authorization = false # Not supported yet by CAF Modules 5.6.1
creation_policies = {
logged_in_user = {
@ -15,19 +16,40 @@ keyvaults = {
secret_permissions = ["Set", "Get", "List", "Delete", "Purge", "Recover"]
certificate_permissions = ["Create", "Get", "List", "Delete", "Purge", "Recover"]
}
ingress_msi = {
ingress_umi = {
managed_identity_key = "ingress"
secret_permissions = ["Get"]
certificate_permissions = ["Get"]
}
apgw_keyvault_secrets = {
apgw_keyvault_secrets_umi = {
managed_identity_key = "apgw_keyvault_secrets"
certificate_permissions = ["Get"]
secret_permissions = ["Get"]
}
}
network = {
bypass = "AzureServices"
default_action = "Allow" # Set the default_action to "Deny" when CICD self-hosted runner is connected to any subnet
subnets = {
subnethub = {
vnet_key = "vnet_hub_re1"
subnet_key = "AzureBastionSubnet"
}
subnetspoke = {
vnet_key = "vnet_aks_re1"
subnet_key = "aks_nodepool_system"
}
}
}
diagnostic_profiles = {
operations = {
name = "akv_logs"
definition_key = "azure_key_vault"
destination_type = "log_analytics"
destination_key = "central_logs"
}
}
}
}

Просмотреть файл

@ -1,4 +1,19 @@
diagnostics_definition = {
azure_application_gateway = {
name = "agw_logs_and_metrics"
categories = {
log = [
# ["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period]
["ApplicationGatewayAccessLog", true, false, 7],
["ApplicationGatewayPerformanceLog", true, false, 7],
["ApplicationGatewayFirewallLog", true, false, 7],
]
metric = [
#["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period]
["AllMetrics", true, false, 7],
]
}
}
azure_container_registry = {
name = "operational_logs_and_metrics"
categories = {
@ -13,6 +28,20 @@ diagnostics_definition = {
]
}
}
azure_key_vault = {
name = "operational_logs_and_metrics"
categories = {
log = [
# ["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period]
["AuditEvent", true, false, 7],
["AzurePolicyEvaluationDetails", true, false, 7],
]
metric = [
#["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period]
["AllMetrics", true, false, 7],
]
}
}
azure_kubernetes_cluster = {
name = "aks_logs_and_metrics"
categories = {

Просмотреть файл

@ -1,8 +1,9 @@
azurerm_firewall_application_rule_collection_definition = {
aks = {
name = "aks"
action = "Allow"
priority = 100
name = "aks"
action = "Allow"
firewall_policy_key = "policies"
priority = 100
ruleset = {
aks = {
name = "aks"

Просмотреть файл

@ -1,9 +1,10 @@
azurerm_firewall_network_rule_collection_definition = {
aks = {
name = "aks"
action = "Allow"
priority = 150
name = "aks"
action = "Allow"
firewall_policy_key = "base_policy"
priority = 150
ruleset = {
ntp = {
name = "ntp"

Просмотреть файл

@ -0,0 +1,32 @@
azurerm_firewall_policies = {
base_policy = {
name = "fw-policies-base"
resource_group_key = "vnet_hub_re1"
sku = "Premium"
threat_intelligence_mode = "Deny"
dns = {
proxy_enabled = true
}
intrusion_detection = {
mode = "Deny"
}
}
policies = {
name = "fw-policies"
resource_group_key = "vnet_hub_re1"
sku = "Premium"
threat_intelligence_mode = "Deny"
dns = {
proxy_enabled = true
}
intrusion_detection = {
mode = "Deny"
}
}
}

Просмотреть файл

@ -18,9 +18,10 @@ vnets = {
}
subnets = {
AzureBastionSubnet = {
name = "AzureBastionSubnet" #Must be called AzureBastionSubnet
cidr = ["10.200.0.96/27"]
nsg_key = "azure_bastion_nsg"
name = "AzureBastionSubnet" #Must be called AzureBastionSubnet
cidr = ["10.200.0.96/27"]
nsg_key = "azure_bastion_nsg"
service_endpoints = ["Microsoft.KeyVault"]
}
}
}
@ -33,10 +34,11 @@ vnets = {
}
subnets = {
aks_nodepool_system = {
name = "snet-clusternodes"
cidr = ["10.240.0.0/22"]
nsg_key = "azure_kubernetes_cluster_nsg"
route_table_key = "default_to_firewall_re1"
name = "snet-clusternodes"
cidr = ["10.240.0.0/22"]
nsg_key = "azure_kubernetes_cluster_nsg"
route_table_key = "default_to_firewall_re1"
service_endpoints = ["Microsoft.KeyVault"]
}
aks_ingress = {
name = "snet-clusteringressservices"

Просмотреть файл

@ -7,10 +7,8 @@ resource_groups = {
name = "rg-enterprise-networking-hubs"
region = "region1"
}
aks_spoke_re1 = {
name = "rg-enterprise-networking-spokes"
region = "region1"
}
}

Просмотреть файл

@ -1,10 +1,10 @@
aks_cluster_key = "cluster_re1"
flux_settings = {
aks_secure_baseline = {
aks_baseline = {
namespace = "flux-system"
url = "https://github.com/Azure/caf-terraform-landingzones-starter.git"
branch = "starter"
target_path = "./enterprise_scale/construction_sets/aks/online/aks_secure_baseline/cluster-baseline-settings/flux"
url = "https://github.com/azure/aks-baseline-automation.git"
branch = "main"
target_path = "./IaC/terraform/cluster-baseline-settings/flux"
}
}

Просмотреть файл

@ -1,10 +1,10 @@
module "flux_addon" {
source = "./add-ons/flux"
flux_settings = var.flux_settings
aks_clusters = module.caf.aks_clusters
caf_config = module.caf
aks_cluster_key = var.aks_cluster_key
}
output "flux_addon_output" {
value = module.flux_addon
value = module.flux_addon.flux_output
}

42
IaC/terraform/locals.tf Normal file
Просмотреть файл

@ -0,0 +1,42 @@
# locals variables created as a helper to pass variables from the GitHub workflow
locals {
resource_groups = { for k, v in var.resource_groups : k =>
{
name = length(var.regions) == 0 ? "${v.name}-${var.global_settings.regions[v.region]}" : "${v.name}-${var.regions[0]}"
region = v.region
}
}
global_settings = length(var.regions) == 0 ? var.global_settings : {
default_region = "region1"
regions = { for region in var.regions : "region${index(var.regions, region) + 1}" => region }
passthrough = true
}
role_mapping_aks_clusters = {
aks_clusters = {
cluster_re1 = {
"Azure Kubernetes Service RBAC Cluster Admin" = {
object_ids = {
keys = compact(var.clusterAdminAADGroupsObjectIds)
}
}
"Azure Kubernetes Service Cluster User Role" = {
object_ids = {
keys = var.clusterAdminAADGroupsObjectIds == var.clusterUserAADGroupsObjectIds ? compact(var.clusterUserAADGroupsObjectIds) : compact(concat(var.clusterAdminAADGroupsObjectIds, var.clusterUserAADGroupsObjectIds))
}
}
"Azure Kubernetes Service RBAC Reader" = {
object_ids = {
keys = compact(var.clusterUserAADGroupsObjectIds)
}
}
}
}
}
partial_role_mapping_merged = merge(var.role_mapping.built_in_role_mapping, local.role_mapping_aks_clusters)
role_mapping = {
built_in_role_mapping = local.partial_role_mapping_merged
}
}

Просмотреть файл

@ -2,54 +2,62 @@ terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "~> 2.88.1"
version = "~> 2.99.0"
}
azuread = {
source = "hashicorp/azuread"
version = "~> 1.4.0"
}
random = {
source = "hashicorp/random"
version = "~> 2.2.1"
}
null = {
source = "hashicorp/null"
version = "~> 2.1.0"
}
external = {
source = "hashicorp/external"
version = "~> 1.2.0"
}
time = {
source = "hashicorp/time"
version = "~> 0.6.0"
}
tls = {
source = "hashicorp/tls"
version = "~> 3.0.0"
azapi = {
source = "azure/azapi"
version = "~> 1.0.0"
}
azurecaf = {
source = "aztfmod/azurecaf"
version = "~> 1.2.0"
version = "~> 1.2.20"
}
random = {
source = "hashicorp/random"
version = "~> 3.3.1"
}
null = {
source = "hashicorp/null"
version = "~> 3.1.1"
}
external = {
source = "hashicorp/external"
version = "~> 2.2.2"
}
time = {
source = "hashicorp/time"
version = "~> 0.8.0"
}
tls = {
source = "hashicorp/tls"
version = "~> 4.0.3"
}
kubernetes = {
source = "hashicorp/kubernetes"
version = ">= 2.0.2"
version = "~> 2.14.0"
}
kubectl = {
source = "gavinbunney/kubectl"
version = ">= 1.11.1"
version = "~> 1.14.0"
}
kustomization = {
source = "kbst/kustomization"
version = "~> 0.9.0"
}
flux = {
source = "fluxcd/flux"
version = ">= 0.0.14"
version = "~> 0.19.0"
}
}
required_version = ">= 0.13"
required_version = ">= 1.3.0"
# comment it out for the local backend experience
# backend "azurerm" {}
backend "azurerm" {}
}
@ -57,7 +65,11 @@ provider "azurerm" {
partner_id = "451dc593-a3a3-4d41-91e7-3aadf93e1a78"
features {
key_vault {
purge_soft_delete_on_destroy = true
purge_soft_delete_on_destroy = true
recover_soft_deleted_key_vaults = true
# TODO with AzureRM 3.0.0+: Uncomment the 2 lines below
# purge_soft_deleted_certificates_on_destroy = true
# recover_soft_deleted_certificates = true
}
}
}
@ -71,5 +83,3 @@ provider "azurerm" {
}
data "azurerm_client_config" "default" {}

Просмотреть файл

@ -1,18 +1,19 @@
module "caf" {
source = "aztfmod/caf/azurerm"
version = "~> 5.5.0"
# source = "./public"
source = "git::https://github.com/aztfmod/terraform-azurerm-caf"
#source = "aztfmod/caf/azurerm"
#version = "~> 5.6.3"
providers = {
azurerm.vhub = azurerm.vhub
}
global_settings = merge((var.override_prefix == "" ? {} : { prefix = var.override_prefix }), var.global_settings)
global_settings = merge((var.override_prefix == "" ? {} : { prefix = var.override_prefix }), local.global_settings)
logged_user_objectId = var.logged_user_objectId
tags = var.tags
resource_groups = var.resource_groups
resource_groups = local.resource_groups
keyvaults = var.keyvaults
managed_identities = var.managed_identities
role_mapping = var.role_mapping
role_mapping = local.role_mapping
azuread = {
azuread_apps = var.azuread_apps
azuread_users = var.azuread_users
@ -20,9 +21,8 @@ module "caf" {
}
networking = {
application_gateways = var.application_gateways
application_gateway_waf_policies = var.application_gateway_waf_policies
application_gateway_platforms = var.application_gateway_platforms
application_gateway_applications = var.application_gateway_applications
application_gateway_applications_v1 = var.application_gateway_applications_v1
domain_name_registrations = var.domain_name_registrations
dns_zone_records = var.dns_zone_records
@ -57,5 +57,4 @@ module "caf" {
security = {
keyvault_certificate_requests = var.keyvault_certificate_requests
}
}

Просмотреть файл

@ -1,6 +1,6 @@
# module "pod_identity_addon" {
# source = "./add-ons/aad-pod-identity"
# aks_clusters = module.caf.aks_clusters
# caf_config = module.caf
# aks_cluster_key = var.aks_cluster_key
# managed_identities = module.caf.managed_identities
# aad_pod_identity = var.aad_pod_identity

Просмотреть файл

@ -7,6 +7,9 @@ resource "azurerm_role_assignment" "kubelet_ingressmsi_miop" {
}
data "azurerm_resource_group" "noderg" {
depends_on = [
module.caf.aks_clusters
]
for_each = module.caf.aks_clusters
name = each.value.node_resource_group
}

Просмотреть файл

@ -50,4 +50,158 @@ eval terraform destroy ${parameter_files}
## Install Sample App
Follow the next step at [terraform-manual-workload](./terraform-manual-workload.md) to deploy Traefik and a sample ASP.NET application
# Deploy AKS Applications
## Deploy cluster baseline settings via Flux
Flux V2 and [infrastructure configurations](../IaC/terraform/cluster-baseline-settings) are installed automatically by the Terraform module.
If you are following the manual approach, then perform the instructions below:
Make sure the current folder is "*IaC/terraform*"
If not use the below command:
```bash
cd IaC/terraform
```
```bash
# Login to the AKS in current user
echo $(terraform output -json | jq -r .aks_clusters_kubeconfig.value.cluster_re1.aks_kubeconfig_cmd) | bash
# If there is lack of RBAC permission in your user role, login with Admin (not recommended for Production)
echo $(terraform output -json | jq -r .aks_clusters_kubeconfig.value.cluster_re1.aks_kubeconfig_admin_cmd) | bash
# Make sure logged in
kubectl get pods -A
```
```
Please review the Baseline components that are deployed at [cluster-baseline-settings](../terraform/cluster-baseline-settings):
- AAD Pod Identity
- AKV Secret Store CSI Driver
- Ingress Network Policy
```bash
# Watch configurations deployment, Ctrl-C to quit
kubectl get pod -n cluster-baseline-settings -w
```
Flux pulls yaml files from [cluster-baseline-settings](../IaC/terraform/cluster-baseline-settings) and applies them to the cluster.
If there is a need to change the folder to your own, please modify [flux.yaml](../IaC/terraform/cluster-baseline-settings/flux/flux.yaml)
## Deploy sample workload Automatically
To deploy a sample app on top of the AKS infrastructure built automatically or manually using terraform, refer to the README under the folder [../workloads](../workloads)
## Deploy sample workload Manually
Follow the steps below to dpeloy a sample workload manually.
1. Get the AKS Ingress Controller Managed Identity details.
```bash
export TRAEFIK_USER_ASSIGNED_IDENTITY_RESOURCE_ID=$(terraform output -json | jq -r .managed_identities.value.ingress.id)
export TRAEFIK_USER_ASSIGNED_IDENTITY_CLIENT_ID=$(terraform output -json | jq -r .managed_identities.value.ingress.client_id)
```
1. Ensure Flux has created the following namespace.
```bash
# press Ctrl-C once you receive a successful response
kubectl get ns a0008
```
1. Create Traefik's Azure Managed Identity binding.
> Create the Traefik Azure Identity and the Azure Identity Binding to let Azure Active Directory Pod Identity to get tokens on behalf of the Traefik's User Assigned Identity and later on assign them to the Traefik's pod.
```yaml
cat <<EOF | kubectl create -f -
apiVersion: aadpodidentity.k8s.io/v1
kind: AzureIdentity
metadata:
name: podmi-ingress-controller-identity
namespace: a0008
spec:
type: 0
resourceID: $TRAEFIK_USER_ASSIGNED_IDENTITY_RESOURCE_ID
clientID: $TRAEFIK_USER_ASSIGNED_IDENTITY_CLIENT_ID
---
apiVersion: aadpodidentity.k8s.io/v1
kind: AzureIdentityBinding
metadata:
name: podmi-ingress-controller-binding
namespace: a0008
spec:
azureIdentity: podmi-ingress-controller-identity
selector: podmi-ingress-controller
EOF
```
1. Create the Traefik's Secret Provider Class resource.
> The Ingress Controller will be exposing the wildcard TLS certificate you created in a prior step. It uses the Azure Key Vault CSI Provider to mount the certificate which is managed and stored in Azure Key Vault. Once mounted, Traefik can use it.
>
> Create a `SecretProviderClass` resource with with your Azure Key Vault parameters for the [Azure Key Vault Provider for Secrets Store CSI driver](https://github.com/Azure/secrets-store-csi-driver-provider-azure).
```bash
KEYVAULT_NAME=$(terraform output -json | jq -r .keyvaults.value.secrets.name)
TENANTID_AZURERBAC=$(az account show --query tenantId -o tsv)
```
```yaml
cat <<EOF | kubectl apply -f -
apiVersion: secrets-store.csi.x-k8s.io/v1alpha1
kind: SecretProviderClass
metadata:
name: aks-ingress-contoso-com-tls-secret-csi-akv
namespace: a0008
spec:
provider: azure
parameters:
usePodIdentity: "true"
keyvaultName: $KEYVAULT_NAME
objects: |
array:
- |
objectName: wildcard-ingress
objectAlias: tls.crt
objectType: cert
- |
objectName: wildcard-ingress
objectAlias: tls.key
objectType: secret
tenantId: $TENANTID_AZURERBAC
EOF
```
2. Deploy Traefik & ASP.net sample application
```bash
kubectl apply -f ./workloads
# It takes 2-3 mins to deploy Traefik & the sample app. Watch all pods to be provision with, press Ctrl + C to exit from watch:
kubectl get pods -n a0008 -w
# Ensure sample app ingress has IP assigned
kubectl get ingress -n a0008
# This website will be available at the public domain below
terraform output -json | jq -r '"https://" + (.domain_name_registrations.value.random_domain.dns_domain_registration_name)'
```
3. You can now test the application from a browser. After couple of the minutes the application gateway health check warning should disappear
## Destroy resources
When finished, please destroy all deployments with:
```bash
# Delete sample application, this contains PodDisruptionBudget that will block Terraform destroy
kubectl delete -f ./workload
# remove to bypass the "context deadline exceeded" error from flux provider
terraform state rm 'module.flux_addon'
# (When needed) Destroy the resources
eval terraform destroy ${parameter_files}
# or if you are facing destroy issues
eval terraform destroy \
${parameter_files} \
-refresh=false
```

Просмотреть файл

@ -6,11 +6,17 @@ variable "global_settings" {
random_length = 4
default_region = "region1"
regions = {
region1 = "southeastasia"
region1 = "eastus"
}
}
}
variable "regions" {
description = "global_settings Azure regions"
type = list(string)
default = []
}
variable "resource_groups" {
default = {}
}
@ -65,6 +71,18 @@ variable "role_mapping" {
default = {}
}
variable "clusterAdminAADGroupsObjectIds" {
description = "K8S Admin Azure AAD Groups ObjectIDs"
type = list(string)
default = []
}
variable "clusterUserAADGroupsObjectIds" {
description = "K8S Reader Azure AAD Groups ObjectIDs"
type = list(string)
default = []
}
variable "keyvaults" {
default = {}
}
@ -73,6 +91,10 @@ variable "azurerm_firewalls" {
default = {}
}
variable "azurerm_firewall_policies" {
default = {}
}
variable "azurerm_firewall_application_rule_collection_definition" {
default = {}
}
@ -125,11 +147,15 @@ variable "dns_zones" {
default = {}
}
variable "application_gateways" {
variable "application_gateway_waf_policies" {
default = {}
}
variable "application_gateway_applications" {
variable "application_gateway_platforms" {
default = {}
}
variable "application_gateway_applications_v1" {
default = {}
}
@ -159,11 +185,3 @@ variable "aad_pod_identity" {
variable "azure_container_registries" {
default = {}
}
variable "application_gateway_platforms" {
default = {}
}
variable "application_gateway_applications_v1" {
default = {}
}