diff --git a/.github/workflows/deploy-aks-online-landingzone.yaml b/.github/workflows/deploy-aks-online-landingzone.yaml
new file mode 100644
index 00000000..fb4bae35
--- /dev/null
+++ b/.github/workflows/deploy-aks-online-landingzone.yaml
@@ -0,0 +1,467 @@
+name: Deploy_AKS_Online_Landingzone
+# The pipeline is triggered on:
+# - PR/Issue comments "/deploy-all", "/deploy-launchpad", "/deploy-shared-services", "/deploy-networking-hub",
+# "/deploy-networking-spoke", "/deploy-aks", "/deploy-addons"
+
+on:
+ workflow_dispatch:
+ push:
+ branches:
+ - CSE-AKS-terratest
+ # issue_comment:
+ # types:
+ # - created
+
+env:
+ AZURE_CREDENTIALS: '{"clientId":"${{ secrets.ARM_CLIENT_ID }}", "clientSecret":"${{ secrets.ARM_CLIENT_SECRET }}", "subscriptionId":"${{ secrets.ARM_SUBSCRIPTION_ID }}", "tenantId":"${{ secrets.ARM_TENANT_ID }}"}'
+ event_sha: +refs/pull/${{ github.event.issue.number }}/merge
+ ARM_CLIENT_ID: ${{ secrets.ARM_CLIENT_ID }}
+ ARM_CLIENT_SECRET: ${{ secrets.ARM_CLIENT_SECRET }}
+ ARM_SUBSCRIPTION_ID: ${{ secrets.ARM_SUBSCRIPTION_ID }}
+ ARM_TENANT_ID: ${{ secrets.ARM_TENANT_ID }}
+ ARM_PARTNER_ID: "f85b2775-ec1d-4fef-949e-bbd6957082af"
+ ENVIRONMENT: ${{ github.run_id }}
+
+jobs:
+ deploy-launchpad:
+ runs-on: ubuntu-latest
+ container:
+ image: aztfmod/rover:1.0.1-2106.3012
+ options: --user 0
+ outputs:
+ prefix: ${{ steps.test.outputs.PREFIX }}
+ steps:
+ - name: Checkout Repository
+ if: contains(github.event.comment.body, '/deploy-all') || contains(github.event.comment.body, '/deploy-launchpad') || github.event_name != 'issue_comment'
+ uses: actions/checkout@v2
+ - name: Checkout PR code
+ if: contains(github.event.comment.body, '/deploy-all') || contains(github.event.comment.body, '/deploy-launchpad')
+ run: |
+ git fetch origin ${{ env.event_sha }}
+ git checkout FETCH_HEAD
+
+ - name: Azure Login
+ if: contains(github.event.comment.body, '/deploy-all') || contains(github.event.comment.body, '/deploy-launchpad') || github.event_name != 'issue_comment'
+ uses: azure/login@v1
+ with:
+ creds: ${{ env.AZURE_CREDENTIALS }}
+
+ - name: Launchpad
+ if: contains(github.event.comment.body, '/deploy-all') || contains(github.event.comment.body, '/deploy-launchpad') || github.event_name != 'issue_comment'
+ run: |
+ cp -rs ${GITHUB_WORKSPACE}/* /tf/caf && cp -r ${GITHUB_WORKSPACE}/.devcontainer /tf/caf/
+ /tf/caf/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/scripts/launchpad.sh
+ - name: Test
+ id: test
+ if: contains(github.event.comment.body, '/deploy-all') || contains(github.event.comment.body, '/deploy-launchpad') || github.event_name != 'issue_comment'
+ run: |
+ cd /tf/caf/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/test
+ export ACTION="output -json -o /tf/caf/rover.output"
+ /tf/caf/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/scripts/launchpad.sh
+ prefix_output=$(cat /tf/caf/rover.output | jq -r .objects.value.launchpad.global_settings.prefixes[0])
+ echo $prefix_output
+ echo "PREFIX"
+ export PREFIX=$prefix_output
+ echo "::set-output name=PREFIX::$prefix_output"
+ go test -v launchpad/launchpad_test.go
+
+
+ deploy-shared-services:
+ runs-on: ubuntu-latest
+ needs: deploy-launchpad
+ container:
+ image: aztfmod/rover:1.0.1-2106.3012
+ options: --user 0
+ outputs:
+ prefix: ${{ steps.test.outputs.PREFIX }}
+ steps:
+ - name: Checkout Repository
+ if: contains(github.event.comment.body, '/deploy-all') || contains(github.event.comment.body, '/deploy-shared-services') || github.event_name != 'issue_comment'
+ uses: actions/checkout@v2
+ - name: Checkout PR code
+ if: contains(github.event.comment.body, '/deploy-all') || contains(github.event.comment.body, '/deploy-shared-services')
+ run: |
+ git fetch origin ${{ env.event_sha }}
+ git checkout FETCH_HEAD
+
+ - name: Azure Login
+ if: contains(github.event.comment.body, '/deploy-all') || contains(github.event.comment.body, '/deploy-shared-services') || github.event_name != 'issue_comment'
+ uses: azure/login@v1
+ with:
+ creds: ${{ env.AZURE_CREDENTIALS }}
+
+ - name: Deploy
+ if: contains(github.event.comment.body, '/deploy-all') || contains(github.event.comment.body, '/deploy-shared-services') || github.event_name != 'issue_comment'
+ run: |
+ cp -rs ${GITHUB_WORKSPACE}/* /tf/caf && cp -r ${GITHUB_WORKSPACE}/.devcontainer /tf/caf/
+ cd /tf/caf/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/
+ ./scripts/deploy_level_with_rover.sh level1 shared_services
+
+ - name: Test
+ id: test
+ if: contains(github.event.comment.body, '/deploy-all') || contains(github.event.comment.body, '/deploy-shared-services') || github.event_name != 'issue_comment'
+ run: |
+ cd /tf/caf/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/test
+ export PREFIX="${{needs.deploy-launchpad.outputs.prefix}}"
+ echo "::set-output name=PREFIX::$PREFIX"
+ go test -v shared_services/shared_services_test.go
+
+ deploy-networking-hub:
+ runs-on: ubuntu-latest
+ needs: deploy-launchpad
+ container:
+ image: aztfmod/rover:1.0.1-2106.3012
+ options: --user 0
+ steps:
+ - name: Checkout Repository
+ if: contains(github.event.comment.body, '/deploy-all') || contains(github.event.comment.body, '/deploy-networking-hub') || github.event_name != 'issue_comment'
+ uses: actions/checkout@v2
+ - name: Checkout PR code
+ if: contains(github.event.comment.body, '/deploy-all') || contains(github.event.comment.body, '/deploy-networking-hub')
+ run: |
+ git fetch origin ${{ env.event_sha }}
+ git checkout FETCH_HEAD
+
+ - name: Azure Login
+ if: contains(github.event.comment.body, '/deploy-all') || contains(github.event.comment.body, '/deploy-networking-hub') || github.event_name != 'issue_comment'
+ uses: azure/login@v1
+ with:
+ creds: ${{ env.AZURE_CREDENTIALS }}
+
+ - name: Deploy
+ if: contains(github.event.comment.body, '/deploy-all') || contains(github.event.comment.body, '/deploy-networking-hub') || github.event_name != 'issue_comment'
+ run: |
+ cp -rs ${GITHUB_WORKSPACE}/* /tf/caf && cp -r ${GITHUB_WORKSPACE}/.devcontainer /tf/caf/
+ cd /tf/caf/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/
+ ./scripts/deploy_level_with_rover.sh level1 networking_hub
+
+ - name: Test
+ if: contains(github.event.comment.body, '/deploy-all') || contains(github.event.comment.body, '/deploy-networking-hub') || github.event_name != 'issue_comment'
+ run: |
+ echo "Invoke integration test"
+
+ deploy-networking-spoke:
+ runs-on: ubuntu-latest
+ needs: deploy-networking-hub
+ container:
+ image: aztfmod/rover:1.0.1-2106.3012
+ options: --user 0
+ steps:
+ - name: Checkout Repository
+ if: contains(github.event.comment.body, '/deploy-all') || contains(github.event.comment.body, '/deploy-networking-spoke') || github.event_name != 'issue_comment'
+ uses: actions/checkout@v2
+ - name: Checkout PR code
+ if: contains(github.event.comment.body, '/deploy-all') || contains(github.event.comment.body, '/deploy-networking-spoke')
+ run: |
+ git fetch origin ${{ env.event_sha }}
+ git checkout FETCH_HEAD
+
+ - name: Azure Login
+ if: contains(github.event.comment.body, '/deploy-all') || contains(github.event.comment.body, '/deploy-networking-spoke') || github.event_name != 'issue_comment'
+ uses: azure/login@v1
+ with:
+ creds: ${{ env.AZURE_CREDENTIALS }}
+
+ - name: Deploy
+ if: contains(github.event.comment.body, '/deploy-all') || contains(github.event.comment.body, '/deploy-networking-spoke') || github.event_name != 'issue_comment'
+ run: |
+ cp -rs ${GITHUB_WORKSPACE}/* /tf/caf && cp -r ${GITHUB_WORKSPACE}/.devcontainer /tf/caf/
+ cd /tf/caf/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/
+ ./scripts/deploy_level_with_rover.sh level1 networking_spoke
+
+ - name: Test
+ if: contains(github.event.comment.body, '/deploy-all') || contains(github.event.comment.body, '/deploy-networking-spoke') || github.event_name != 'issue_comment'
+ run: |
+ echo "Invoke integration test"
+
+ deploy-aks:
+ runs-on: ubuntu-latest
+ needs: [deploy-networking-hub, deploy-networking-spoke, deploy-shared-services]
+ container:
+ image: aztfmod/rover:1.0.1-2106.3012
+ options: --user 0
+ outputs:
+ prefix: ${{ steps.test.outputs.PREFIX }}
+ steps:
+ - name: Checkout Repository
+ if: contains(github.event.comment.body, '/deploy-all') || contains(github.event.comment.body, '/deploy-aks') || github.event_name != 'issue_comment'
+ uses: actions/checkout@v2
+ - name: Checkout PR code
+ if: contains(github.event.comment.body, '/deploy-all') || contains(github.event.comment.body, '/deploy-aks')
+ run: |
+ git fetch origin ${{ env.event_sha }}
+ git checkout FETCH_HEAD
+
+ - name: Azure Login
+ if: contains(github.event.comment.body, '/deploy-all') || contains(github.event.comment.body, '/deploy-aks') || github.event_name != 'issue_comment'
+ uses: azure/login@v1
+ with:
+ creds: ${{ env.AZURE_CREDENTIALS }}
+
+ - name: Deploy
+ if: contains(github.event.comment.body, '/deploy-all') || contains(github.event.comment.body, '/deploy-aks') || github.event_name != 'issue_comment'
+ run: |
+ cp -rs ${GITHUB_WORKSPACE}/* /tf/caf && cp -r ${GITHUB_WORKSPACE}/.devcontainer /tf/caf/
+ cd /tf/caf/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/
+ ./scripts/deploy_level_with_rover.sh level2 aks
+
+ - name: Test
+ id: test
+ if: contains(github.event.comment.body, '/deploy-all') || contains(github.event.comment.body, '/deploy-aks') || github.event_name != 'issue_comment'
+ run: |
+ cd /tf/caf/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/test
+ export PREFIX="${{needs.deploy-shared-services.outputs.prefix}}"
+ echo "::set-output name=PREFIX::$PREFIX"
+ go test -v aks/aks_test.go
+
+ deploy-addons:
+ runs-on: ubuntu-latest
+ needs: deploy-aks
+ container:
+ image: aztfmod/rover:1.0.1-2106.3012
+ options: --user 0
+ steps:
+ - name: Checkout Repository
+ if: contains(github.event.comment.body, '/deploy-all') || contains(github.event.comment.body, '/deploy-addons') || github.event_name != 'issue_comment'
+ uses: actions/checkout@v2
+ - name: Checkout PR code
+ if: contains(github.event.comment.body, '/deploy-all') || contains(github.event.comment.body, '/deploy-addons')
+ run: |
+ git fetch origin ${{ env.event_sha }}
+ git checkout FETCH_HEAD
+
+ - name: Azure Login
+ if: contains(github.event.comment.body, '/deploy-all') || contains(github.event.comment.body, '/deploy-addons') || github.event_name != 'issue_comment'
+ uses: azure/login@v1
+ with:
+ creds: ${{ env.AZURE_CREDENTIALS }}
+
+ - name: Deploy
+ if: contains(github.event.comment.body, '/deploy-all') || contains(github.event.comment.body, '/deploy-addons') || github.event_name != 'issue_comment'
+ run: |
+ cp -rs ${GITHUB_WORKSPACE}/* /tf/caf && cp -r ${GITHUB_WORKSPACE}/.devcontainer /tf/caf/
+ cd /tf/caf/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/
+ ./scripts/deploy_level_with_rover.sh level2 aks_secure_baseline /add-ons/aks_secure_baseline_v2
+
+ /tf/rover/rover.sh \
+ -lz /tf/caf/landingzones/caf_solution/add-ons/aks_secure_baseline_v2 \
+ -tfstate aks_secure_baseline.tfstate \
+ -level level2 \
+ -env $ENVIRONMENT \
+ -a output -json -o $(pwd)/rover.output
+ echo $(cat rover.output | jq -r .aks_clusters_kubeconfig.value.aks_kubeconfig_admin_cmd) | bash
+
+
+ - name: Test
+ if: contains(github.event.comment.body, '/deploy-all') || contains(github.event.comment.body, '/deploy-addons') || github.event_name != 'issue_comment'
+ run: |
+ cd /tf/caf/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/test
+ export PREFIX="${{needs.deploy-aks.outputs.prefix}}"
+ go test -v flux/flux_test.go
+ env:
+ KUBECONFIGPATH: /github/home/.kube/config
+
+ destroy-addons:
+ runs-on: ubuntu-latest
+ needs: deploy-addons
+ container:
+ image: aztfmod/rover:1.0.1-2106.3012
+ options: --user 0
+ steps:
+ - name: Checkout Repository
+ if: contains(github.event.comment.body, '/deploy-all') || contains(github.event.comment.body, '/deploy-launchpad') || github.event_name != 'issue_comment'
+ uses: actions/checkout@v2
+ - name: Checkout PR code
+ if: contains(github.event.comment.body, '/deploy-all') || contains(github.event.comment.body, '/deploy-launchpad')
+ run: |
+ git fetch origin ${{ env.event_sha }}
+ git checkout FETCH_HEAD
+ - name: Azure Login
+ if: contains(github.event.comment.body, '/destroy-all') || contains(github.event.comment.body, '/destroy-addons') || github.event_name != 'issue_comment'
+ uses: azure/login@v1
+ with:
+ creds: ${{ env.AZURE_CREDENTIALS }}
+
+ - name: Destroy
+ if: contains(github.event.comment.body, '/destroy-all') || contains(github.event.comment.body, '/destroy-addons') || github.event_name != 'issue_comment'
+ run: |
+ cp -rs ${GITHUB_WORKSPACE}/* /tf/caf && cp -r ${GITHUB_WORKSPACE}/.devcontainer /tf/caf/
+ cd /tf/caf/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/
+ ./scripts/deploy_level_with_rover.sh level2 aks_secure_baseline /add-ons/aks_secure_baseline_v2
+ env:
+ ACTION: "destroy -auto-approve"
+
+ destroy-aks:
+ runs-on: ubuntu-latest
+ needs: [destroy-addons]
+ container:
+ image: aztfmod/rover:1.0.1-2106.3012
+ options: --user 0
+ steps:
+ - name: Checkout Repository
+ if: contains(github.event.comment.body, '/deploy-all') || contains(github.event.comment.body, '/deploy-launchpad') || github.event_name != 'issue_comment'
+ uses: actions/checkout@v2
+ - name: Checkout PR code
+ if: contains(github.event.comment.body, '/deploy-all') || contains(github.event.comment.body, '/deploy-launchpad')
+ run: |
+ git fetch origin ${{ env.event_sha }}
+ git checkout FETCH_HEAD
+ - name: Azure Login
+ if: contains(github.event.comment.body, '/destroy-all') || contains(github.event.comment.body, '/destroy-aks') || github.event_name != 'issue_comment'
+ uses: azure/login@v1
+ with:
+ creds: ${{ env.AZURE_CREDENTIALS }}
+ - name: Destroy
+ if: contains(github.event.comment.body, '/destroy-all') || contains(github.event.comment.body, '/destroy-aks') || github.event_name != 'issue_comment'
+ run: |
+ cp -rs ${GITHUB_WORKSPACE}/* /tf/caf && cp -r ${GITHUB_WORKSPACE}/.devcontainer /tf/caf/
+ cd /tf/caf/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/
+ ./scripts/deploy_level_with_rover.sh level2 aks
+ env:
+ ACTION: "destroy -auto-approve"
+
+ destroy-shared-services:
+ runs-on: ubuntu-latest
+ needs: destroy-aks
+ container:
+ image: aztfmod/rover:1.0.1-2106.3012
+ options: --user 0
+ steps:
+ - name: Checkout Repository
+ if: contains(github.event.comment.body, '/deploy-all') || contains(github.event.comment.body, '/deploy-launchpad') || github.event_name != 'issue_comment'
+ uses: actions/checkout@v2
+ - name: Checkout PR code
+ if: contains(github.event.comment.body, '/deploy-all') || contains(github.event.comment.body, '/deploy-launchpad')
+ run: |
+ git fetch origin ${{ env.event_sha }}
+ git checkout FETCH_HEAD
+ - name: Azure Login
+ if: contains(github.event.comment.body, '/destroy-all') || contains(github.event.comment.body, '/destroy-shared-services') || github.event_name != 'issue_comment'
+ uses: azure/login@v1
+ with:
+ creds: ${{ env.AZURE_CREDENTIALS }}
+
+ - name: Destroy
+ if: contains(github.event.comment.body, '/destroy-all') || contains(github.event.comment.body, '/destroy-shared-services') || github.event_name != 'issue_comment'
+ run: |
+ cp -rs ${GITHUB_WORKSPACE}/* /tf/caf && cp -r ${GITHUB_WORKSPACE}/.devcontainer /tf/caf/
+ cd /tf/caf/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/
+ ./scripts/deploy_level_with_rover.sh level1 shared_services
+ env:
+ ACTION: "destroy -auto-approve"
+
+ destroy-networking-spoke:
+ runs-on: ubuntu-latest
+ needs: destroy-aks
+ container:
+ image: aztfmod/rover:1.0.1-2106.3012
+ options: --user 0
+ steps:
+ - name: Checkout Repository
+ if: contains(github.event.comment.body, '/deploy-all') || contains(github.event.comment.body, '/deploy-launchpad') || github.event_name != 'issue_comment'
+ uses: actions/checkout@v2
+ - name: Checkout PR code
+ if: contains(github.event.comment.body, '/deploy-all') || contains(github.event.comment.body, '/deploy-launchpad')
+ run: |
+ git fetch origin ${{ env.event_sha }}
+ git checkout FETCH_HEAD
+ - name: Azure Login
+ if: contains(github.event.comment.body, '/destroy-all') || contains(github.event.comment.body, '/destroy-networking-spoke') || github.event_name != 'issue_comment'
+ uses: azure/login@v1
+ with:
+ creds: ${{ env.AZURE_CREDENTIALS }}
+
+ - name: Destroy
+ if: contains(github.event.comment.body, '/destroy-all') || contains(github.event.comment.body, '/destroy-networking-spoke') || github.event_name != 'issue_comment'
+ run: |
+ cp -rs ${GITHUB_WORKSPACE}/* /tf/caf && cp -r ${GITHUB_WORKSPACE}/.devcontainer /tf/caf/
+ cd /tf/caf/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/
+ ./scripts/deploy_level_with_rover.sh level1 networking_spoke
+ env:
+ ACTION: "destroy -auto-approve"
+
+ destroy-networking-hub:
+ runs-on: ubuntu-latest
+ needs: destroy-networking-spoke
+ container:
+ image: aztfmod/rover:1.0.1-2106.3012
+ options: --user 0
+ steps:
+ - name: Checkout Repository
+ if: contains(github.event.comment.body, '/deploy-all') || contains(github.event.comment.body, '/deploy-launchpad') || github.event_name != 'issue_comment'
+ uses: actions/checkout@v2
+ - name: Checkout PR code
+ if: contains(github.event.comment.body, '/deploy-all') || contains(github.event.comment.body, '/deploy-launchpad')
+ run: |
+ git fetch origin ${{ env.event_sha }}
+ git checkout FETCH_HEAD
+ - name: Azure Login
+ if: contains(github.event.comment.body, '/destroy-all') || contains(github.event.comment.body, '/destroy-networking-hub') || github.event_name != 'issue_comment'
+ uses: azure/login@v1
+ with:
+ creds: ${{ env.AZURE_CREDENTIALS }}
+
+ - name: Destroy
+ if: contains(github.event.comment.body, '/destroy-all') || contains(github.event.comment.body, '/destroy-networking-hub') || github.event_name != 'issue_comment'
+ run: |
+ cp -rs ${GITHUB_WORKSPACE}/* /tf/caf && cp -r ${GITHUB_WORKSPACE}/.devcontainer /tf/caf/
+ cd /tf/caf/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/
+ ./scripts/deploy_level_with_rover.sh level1 networking_hub
+ env:
+ ACTION: "destroy -auto-approve"
+
+ destroy-launchpad:
+ runs-on: ubuntu-latest
+ needs: [destroy-networking-hub, destroy-shared-services]
+ container:
+ image: aztfmod/rover:1.0.1-2106.3012
+ options: --user 0
+ steps:
+ - name: Checkout Repository
+ if: contains(github.event.comment.body, '/deploy-all') || contains(github.event.comment.body, '/deploy-launchpad') || github.event_name != 'issue_comment'
+ uses: actions/checkout@v2
+ - name: Checkout PR code
+ if: contains(github.event.comment.body, '/deploy-all') || contains(github.event.comment.body, '/deploy-launchpad')
+ run: |
+ git fetch origin ${{ env.event_sha }}
+ git checkout FETCH_HEAD
+ - name: Azure Login
+ if: contains(github.event.comment.body, '/destroy-all') || contains(github.event.comment.body, '/destroy-launchpad') || github.event_name != 'issue_comment'
+ uses: azure/login@v1
+ with:
+ creds: ${{ env.AZURE_CREDENTIALS }}
+
+ - name: Launchpad
+ if: contains(github.event.comment.body, '/destroy-all') || contains(github.event.comment.body, '/destroy-launchpad') || github.event_name != 'issue_comment'
+ run: |
+ cp -rs ${GITHUB_WORKSPACE}/* /tf/caf && cp -r ${GITHUB_WORKSPACE}/.devcontainer /tf/caf/
+ /tf/caf/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/scripts/launchpad.sh
+ env:
+ ACTION: "destroy -auto-approve"
+
+ purge:
+ name: purge
+ runs-on: ubuntu-latest
+ if: ${{ failure() || cancelled() }}
+
+ needs: [deploy-launchpad, deploy-shared-services, deploy-networking-hub, deploy-networking-spoke,deploy-aks, deploy-addons, destroy-addons, destroy-aks, destroy-networking-spoke, destroy-networking-hub, destroy-shared-services, destroy-launchpad]
+
+ container:
+ image: aztfmod/rover:1.0.1-2106.3012
+ options: --user 0
+
+ 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 }}
+ - name: Complete purge
+ run: |
+ for i in `az monitor diagnostic-settings subscription list -o tsv --query "value[?contains(name, '${{ github.run_id }}' )].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, '${{ github.run_id }}')].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, '${{ github.run_id }}')].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=='${{ github.run_id }}'].name" -o tsv`; do az keyvault purge --name $i; done
+ for i in `az group list --query "[?tags.testing_job_id=='${{ github.run_id }}'].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, '${{ github.run_id }}')].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, '${{ github.run_id }}')].roleName" -o tsv`; do echo "purging custom role definition: $i" && $(az role definition delete --name $i || true); done
\ No newline at end of file
diff --git a/.github/workflows/deploy-aks-online-standalone.yaml b/.github/workflows/deploy-aks-online-standalone.yaml
new file mode 100644
index 00000000..4b9737b0
--- /dev/null
+++ b/.github/workflows/deploy-aks-online-standalone.yaml
@@ -0,0 +1,107 @@
+name: Deploy_AKS_Online_Standalone
+# The pipeline is triggered on:
+# - PR/Issue comments "/deploy-all", "/deploy-launchpad", "/deploy-shared-services", "/deploy-networking-hub",
+# "/deploy-networking-spoke", "/deploy-aks", "/deploy-addons"
+
+on:
+ workflow_dispatch:
+ push:
+ branches:
+ - CSE-AKS-terratest
+ # issue_comment:
+ # types:
+ # - created
+
+env:
+ AZURE_CREDENTIALS: '{"clientId":"${{ secrets.ARM_CLIENT_ID }}", "clientSecret":"${{ secrets.ARM_CLIENT_SECRET }}", "subscriptionId":"${{ secrets.ARM_SUBSCRIPTION_ID }}", "tenantId":"${{ secrets.ARM_TENANT_ID }}"}'
+ event_sha: +refs/pull/${{ github.event.issue.number }}/merge
+ ARM_CLIENT_ID: ${{ secrets.ARM_CLIENT_ID }}
+ ARM_CLIENT_SECRET: ${{ secrets.ARM_CLIENT_SECRET }}
+ ARM_SUBSCRIPTION_ID: ${{ secrets.ARM_SUBSCRIPTION_ID }}
+ ARM_TENANT_ID: ${{ secrets.ARM_TENANT_ID }}
+ ARM_PARTNER_ID: "f85b2775-ec1d-4fef-949e-bbd6957082af"
+ ENVIRONMENT: ${{ github.run_id }}
+
+jobs:
+ deploy-standalone:
+ runs-on: ubuntu-latest
+ outputs:
+ prefix: ${{ steps.test.outputs.PREFIX }}
+ steps:
+ - name: Checkout Repository
+ if: contains(github.event.comment.body, '/deploy-all') || contains(github.event.comment.body, '/deploy-launchpad') || github.event_name != 'issue_comment'
+ uses: actions/checkout@v2
+ - name: Checkout PR code
+ if: contains(github.event.comment.body, '/deploy-all') || contains(github.event.comment.body, '/deploy-launchpad')
+ run: |
+ git fetch origin ${{ env.event_sha }}
+ git checkout FETCH_HEAD
+
+ - name: Azure Login
+ if: contains(github.event.comment.body, '/deploy-all') || contains(github.event.comment.body, '/deploy-launchpad') || github.event_name != 'issue_comment'
+ uses: azure/login@v1
+ with:
+ creds: ${{ env.AZURE_CREDENTIALS }}
+
+ - uses: hashicorp/setup-terraform@v1
+ with:
+ terraform_version: 1.0.3
+ terraform_wrapper: false
+ # https://stackoverflow.com/questions/65170927/terraform-output-value-failed-formatted-by-jq-in-github-actions
+
+ - 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 enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/
+ configuration_folder=configuration
+ parameter_files=$(find $configuration_folder -not -path "*launchpad*" | grep .tfvars | sed 's/.*/-var-file &/' | xargs)
+ terraform init -upgrade
+ eval terraform apply ${parameter_files} -var tags='{testing_job_id='"$ENVIRONMENT"'}' -auto-approve
+ - name: Test
+ id: test
+ if: contains(github.event.comment.body, '/deploy-all') || contains(github.event.comment.body, '/deploy-launchpad') || github.event_name != 'issue_comment'
+ run: |
+ pwd
+ cd enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/
+ ls -lta
+ export ARM_SUBSCRIPTION_ID=$(az account show --query id -o tsv)
+ export PREFIX=$(terraform output -json | jq -r '.global_settings.value.prefixes[0]')
+ echo $(terraform output -json | jq -r .aks_clusters_kubeconfig.value.cluster_re1.aks_kubeconfig_admin_cmd) | bash
+
+ cd ../test
+ go mod tidy
+ go test -v shared_services/shared_services_test.go
+ go test -v aks/aks_test.go
+ go test -v flux/flux_test.go
+ - 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 enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone
+ configuration_folder=configuration
+ parameter_files=$(find $configuration_folder -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
+ 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 }}
+ - name: Complete purge
+ run: |
+ for i in `az monitor diagnostic-settings subscription list -o tsv --query "value[?contains(name, '${{ github.run_id }}' )].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, '${{ github.run_id }}')].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, '${{ github.run_id }}')].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=='${{ github.run_id }}'].name" -o tsv`; do az keyvault purge --name $i; done
+ for i in `az group list --query "[?tags.testing_job_id=='${{ github.run_id }}'].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, '${{ github.run_id }}')].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, '${{ github.run_id }}')].roleName" -o tsv`; do echo "purging custom role definition: $i" && $(az role definition delete --name $i || true); done
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 5e652918..4a06f7bd 100644
--- a/.gitignore
+++ b/.gitignore
@@ -18,3 +18,5 @@ landingzones
**/*.key
**/*.pem
**/*.cer
+**/*.output
+*output.json
\ No newline at end of file
diff --git a/.pipelines/deploy-aks-online-landingzone.yaml b/.pipelines/deploy-aks-online-landingzone.yaml
new file mode 100644
index 00000000..e517ed5a
--- /dev/null
+++ b/.pipelines/deploy-aks-online-landingzone.yaml
@@ -0,0 +1,386 @@
+trigger: none
+
+variables:
+ - group: iac-secure-caf
+ - name: "ARM_PARTNER_ID"
+ value: "f85b2775-ec1d-4fef-949e-bbd6957082af"
+ - name: "ENVIRONMENT"
+ value: "$(Build.BuildNumber)"
+
+resources:
+ containers:
+ - container: rover
+ image: $(ROVER_IMAGE)
+ options: --user 0:0 -e TF_PLUGIN_CACHE_DIR="/home/vsts_azpcontainer/plugin-cache" -e TF_DATA_DIR="/home/vsts_azpcontainer"
+
+stages:
+- stage: deploy_launchpad
+ jobs:
+ - job: deploy_launchpad
+ displayName: "Deploy Launchpad"
+ container: rover
+
+ steps:
+ - task: AzureCLI@2
+ displayName: Deploy Launchpad. Level 0.
+ name: deploy_launchpad
+ inputs:
+ azureSubscription: $(AZURE_SERVICE_NAME)
+ scriptLocation: inlineScript
+ scriptType: bash
+ inlineScript: |
+ echo "ENVIRONMENT"
+ echo $ENVIRONMENT
+ cp -rs $(Build.SourcesDirectory)/* /tf/caf && cp -r $(Build.SourcesDirectory)/.devcontainer /tf/caf/
+ /tf/caf/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/scripts/launchpad.sh
+ env:
+ ARM_CLIENT_SECRET: $(ARM_CLIENT_SECRET)
+
+ - task: AzureCLI@2
+ displayName: Launchpad Test
+ name: test
+ inputs:
+ azureSubscription: $(AZURE_SERVICE_NAME)
+ scriptLocation: inlineScript
+ scriptType: bash
+ inlineScript: |
+ cd /tf/caf/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/test
+ export ACTION="output -json -o /tf/caf/rover.output"
+ /tf/caf/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/scripts/launchpad.sh
+ prefix_output=$(cat /tf/caf/rover.output | jq -r .objects.value.launchpad.global_settings.prefixes[0])
+ echo $prefix_output
+ echo "PREFIX"
+ export PREFIX=$prefix_output
+ echo "##vso[task.setvariable variable=PREFIX;isOutput=true]$prefix_output"
+ go test -v launchpad/launchpad_test.go
+ env:
+ ARM_CLIENT_SECRET: $(ARM_CLIENT_SECRET)
+
+- stage: deploy_level1
+ jobs:
+ - job: deploy_shared_services
+ displayName: "Deploy Shared Services. Level 1"
+ container: rover
+ variables:
+ prefix: $[stageDependencies.deploy_launchpad.deploy_launchpad.outputs['test.PREFIX']]
+
+ steps:
+ - task: AzureCLI@2
+ displayName: Deploy Shared Services
+ name: deploy_shared_services
+ inputs:
+ azureSubscription: $(AZURE_SERVICE_NAME)
+ scriptLocation: inlineScript
+ scriptType: bash
+ inlineScript: |
+ cp -rs $(Build.SourcesDirectory)/* /tf/caf && cp -r $(Build.SourcesDirectory)/.devcontainer /tf/caf/
+ cd /tf/caf/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/scripts/
+ ./deploy_level_with_rover.sh level1 shared_services
+ env:
+ ARM_CLIENT_SECRET: $(ARM_CLIENT_SECRET)
+
+ - task: AzureCLI@2
+ displayName: Shared Services Test
+ name: test
+ inputs:
+ azureSubscription: $(AZURE_SERVICE_NAME)
+ scriptLocation: inlineScript
+ scriptType: bash
+ inlineScript: |
+ cd /tf/caf/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/test
+ echo "##vso[task.setvariable variable=PREFIX;isOutput=true]$PREFIX"
+ go test -v shared_services/shared_services_test.go
+ env:
+ PREFIX: $(prefix)
+
+ - job: deploy_networking_hub
+ displayName: "Deploy Networking Hub. Level 1"
+ container: rover
+
+ steps:
+ - task: AzureCLI@2
+ displayName: Deploy Networking Hub
+ name: deploy_networking_hub
+ inputs:
+ azureSubscription: $(AZURE_SERVICE_NAME)
+ scriptLocation: inlineScript
+ scriptType: bash
+ inlineScript: |
+ cp -rs $(Build.SourcesDirectory)/* /tf/caf && cp -r $(Build.SourcesDirectory)/.devcontainer /tf/caf/
+ cd /tf/caf/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/
+ ./scripts/deploy_level_with_rover.sh level1 networking_hub
+ env:
+ ARM_CLIENT_SECRET: $(ARM_CLIENT_SECRET)
+
+ - task: AzureCLI@2
+ displayName: Networking Hub Test
+ inputs:
+ azureSubscription: $(AZURE_SERVICE_NAME)
+ scriptLocation: inlineScript
+ scriptType: bash
+ inlineScript: |
+ echo "Invoke integration test"
+
+ - job: deploy_networking_spoke
+ displayName: "Deploy Networking Spoke. Level 1"
+ dependsOn: deploy_networking_hub
+ container: rover
+
+ steps:
+ - task: AzureCLI@2
+ displayName: Deploy Networking Spoke
+ name: deploy_networking_spoke
+ inputs:
+ azureSubscription: $(AZURE_SERVICE_NAME)
+ scriptLocation: inlineScript
+ scriptType: bash
+ inlineScript: |
+ cp -rs $(Build.SourcesDirectory)/* /tf/caf && cp -r $(Build.SourcesDirectory)/.devcontainer /tf/caf/
+ cd /tf/caf/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/
+ ./scripts/deploy_level_with_rover.sh level1 networking_spoke
+ env:
+ ARM_CLIENT_SECRET: $(ARM_CLIENT_SECRET)
+
+ - task: AzureCLI@2
+ displayName: Networking Spoke Test
+ inputs:
+ azureSubscription: $(AZURE_SERVICE_NAME)
+ scriptLocation: inlineScript
+ scriptType: bash
+ inlineScript: |
+ echo "Invoke integration test"
+
+- stage: deploy_aks
+ jobs:
+ - job: deploy_aks
+ displayName: "Deploy AKS. Level 2"
+ container: rover
+ variables:
+ prefix: $[ stageDependencies.deploy_level1.deploy_shared_services.outputs['test.PREFIX'] ]
+
+ steps:
+ - task: AzureCLI@2
+ displayName: Deploy AKS
+ name: deploy_aks
+ inputs:
+ azureSubscription: $(AZURE_SERVICE_NAME)
+ scriptLocation: inlineScript
+ scriptType: bash
+ inlineScript: |
+ cp -rs $(Build.SourcesDirectory)/* /tf/caf && cp -r $(Build.SourcesDirectory)/.devcontainer /tf/caf/
+ cd /tf/caf/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/
+ ./scripts/deploy_level_with_rover.sh level2 aks
+ env:
+ ARM_CLIENT_SECRET: $(ARM_CLIENT_SECRET)
+
+ - task: AzureCLI@2
+ displayName: AKS Test
+ name: test
+ inputs:
+ azureSubscription: $(AZURE_SERVICE_NAME)
+ scriptLocation: inlineScript
+ scriptType: bash
+ inlineScript: |
+ cd /tf/caf/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/test
+ echo "##vso[task.setvariable variable=PREFIX;isOutput=true]$PREFIX"
+ go test -v aks/aks_test.go
+ env:
+ PREFIX: $(prefix)
+
+- stage: deploy_addons
+ jobs:
+ - job: deploy_addons
+ displayName: "Deploy Addons. Level 2"
+ container: rover
+ variables:
+ prefix: $[ stageDependencies.deploy_aks.deploy_aks.outputs['test.PREFIX'] ]
+
+ steps:
+ - task: AzureCLI@2
+ displayName: Deploy Addons
+ name: deploy_addons
+ inputs:
+ azureSubscription: $(AZURE_SERVICE_NAME)
+ scriptLocation: inlineScript
+ scriptType: bash
+ inlineScript: |
+ cp -rs $(Build.SourcesDirectory)/* /tf/caf && cp -r $(Build.SourcesDirectory)/.devcontainer /tf/caf/
+ cd /tf/caf/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/
+ ./scripts/deploy_level_with_rover.sh level2 aks_secure_baseline /add-ons/aks_secure_baseline_v2
+ /tf/rover/rover.sh \
+ -lz /tf/caf/landingzones/caf_solution/add-ons/aks_secure_baseline_v2 \
+ -tfstate aks_secure_baseline.tfstate \
+ -level level2 \
+ -env $ENVIRONMENT \
+ -a output -json -o $(pwd)/rover.output
+
+ echo $(cat rover.output | jq -r .aks_clusters_kubeconfig.value.aks_kubeconfig_admin_cmd) | bash
+ env:
+ ARM_CLIENT_SECRET: $(ARM_CLIENT_SECRET)
+
+ - task: AzureCLI@2
+ displayName: Addons Test
+ inputs:
+ azureSubscription: $(AZURE_SERVICE_NAME)
+ scriptLocation: inlineScript
+ scriptType: bash
+ inlineScript: |
+ cd /tf/caf/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/test
+ go test -v flux/flux_test.go
+ env:
+ PREFIX: $(prefix)
+ KUBECONFIGPATH: /home/vsts_azpcontainer/.kube/config
+
+- stage: destroy_addons
+ jobs:
+ - job: destroy_addons
+ displayName: "Destroy Addons. Level 2"
+ container: rover
+
+ steps:
+ - task: AzureCLI@2
+ displayName: Destroy Addons
+ name: destroy_addons
+ inputs:
+ azureSubscription: $(AZURE_SERVICE_NAME)
+ scriptLocation: inlineScript
+ scriptType: bash
+ inlineScript: |
+ cp -rs $(Build.SourcesDirectory)/* /tf/caf && cp -r $(Build.SourcesDirectory)/.devcontainer /tf/caf/
+ cd /tf/caf/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/
+ ./scripts/deploy_level_with_rover.sh level2 aks_secure_baseline /add-ons/aks_secure_baseline_v2
+ env:
+ ARM_CLIENT_SECRET: $(ARM_CLIENT_SECRET)
+ ACTION: "destroy -auto-approve"
+
+- stage: destroy_aks
+ jobs:
+ - job: destroy_aks
+ displayName: "Destroy AKS. Level 2"
+ container: rover
+
+ steps:
+ - task: AzureCLI@2
+ displayName: Destroy AKS
+ name: deploy_aks
+ inputs:
+ azureSubscription: $(AZURE_SERVICE_NAME)
+ scriptLocation: inlineScript
+ scriptType: bash
+ inlineScript: |
+ cp -rs $(Build.SourcesDirectory)/* /tf/caf && cp -r $(Build.SourcesDirectory)/.devcontainer /tf/caf/
+ cd /tf/caf/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/
+ ./scripts/deploy_level_with_rover.sh level2 aks
+ env:
+ ARM_CLIENT_SECRET: $(ARM_CLIENT_SECRET)
+ ACTION: "destroy -auto-approve"
+
+- stage: destroy_level1
+ jobs:
+ - job: destroy_networking_spoke
+ displayName: "Destroy Networking Spoke. Level 1"
+ container: rover
+
+ steps:
+ - task: AzureCLI@2
+ displayName: Destroy Networking Spoke
+ name: destroy_networking_spoke
+ inputs:
+ azureSubscription: $(AZURE_SERVICE_NAME)
+ scriptLocation: inlineScript
+ scriptType: bash
+ inlineScript: |
+ cp -rs $(Build.SourcesDirectory)/* /tf/caf && cp -r $(Build.SourcesDirectory)/.devcontainer /tf/caf/
+ cd /tf/caf/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/
+ ./scripts/deploy_level_with_rover.sh level1 networking_spoke
+ env:
+ ARM_CLIENT_SECRET: $(ARM_CLIENT_SECRET)
+ ACTION: "destroy -auto-approve"
+
+ - job: destroy_networking_hub
+ displayName: "Destroy Networking Hub. Level 1"
+ dependsOn: destroy_networking_spoke
+ container: rover
+
+ steps:
+ - task: AzureCLI@2
+ displayName: Destroy Networking Hub
+ name: destroy_networking_hub
+ inputs:
+ azureSubscription: $(AZURE_SERVICE_NAME)
+ scriptLocation: inlineScript
+ scriptType: bash
+ inlineScript: |
+ cp -rs $(Build.SourcesDirectory)/* /tf/caf && cp -r $(Build.SourcesDirectory)/.devcontainer /tf/caf/
+ cd /tf/caf/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/
+ ./scripts/deploy_level_with_rover.sh level1 networking_hub
+ env:
+ ARM_CLIENT_SECRET: $(ARM_CLIENT_SECRET)
+ ACTION: "destroy -auto-approve"
+
+ - job: destroy_shared_services
+ displayName: "Destroy Shared Services. Level 1"
+ container: rover
+
+ steps:
+ - task: AzureCLI@2
+ displayName: Destroy Shared Services
+ name: destroy_shared_services
+ inputs:
+ azureSubscription: $(AZURE_SERVICE_NAME)
+ scriptLocation: inlineScript
+ scriptType: bash
+ inlineScript: |
+ cp -rs $(Build.SourcesDirectory)/* /tf/caf && cp -r $(Build.SourcesDirectory)/.devcontainer /tf/caf/
+ cd /tf/caf/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/scripts/
+ ./deploy_level_with_rover.sh level1 shared_services
+ env:
+ ARM_CLIENT_SECRET: $(ARM_CLIENT_SECRET)
+ ACTION: "destroy -auto-approve"
+- stage: destroy_launchpad
+ jobs:
+ - job: destroy_launchpad
+ displayName: "Destroy Launchpad"
+ container: rover
+
+ steps:
+ - task: AzureCLI@2
+ displayName: Destroy Launchpad. Level 0.
+ name: destroy_launchpad
+ inputs:
+ azureSubscription: $(AZURE_SERVICE_NAME)
+ scriptLocation: inlineScript
+ scriptType: bash
+ inlineScript: |
+ cp -rs $(Build.SourcesDirectory)/* /tf/caf && cp -r $(Build.SourcesDirectory)/.devcontainer /tf/caf/
+ /tf/caf/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/scripts/launchpad.sh
+ env:
+ ARM_CLIENT_SECRET: $(ARM_CLIENT_SECRET)
+ ACTION: "destroy -auto-approve"
+- stage: purge
+ condition: always()
+ jobs:
+ - job: purge
+ displayName: "Purge"
+ container: rover
+
+ steps:
+ - task: AzureCLI@2
+ displayName: Purge
+ name: destroy_launchpad
+ inputs:
+ azureSubscription: $(AZURE_SERVICE_NAME)
+ scriptLocation: inlineScript
+ scriptType: bash
+ inlineScript: |
+ echo BuildNumber $(Build.BuildNumber)
+ for i in `az monitor diagnostic-settings subscription list -o tsv --query "value[?contains(name, '$(Build.BuildNumber)' )].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, '$(Build.BuildNumber)')].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, '$(Build.BuildNumber)')].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=='$(Build.BuildNumber)'].name" -o tsv`; do az keyvault purge --name $i; done
+ for i in `az group list --query "[?tags.testing_job_id=='$(Build.BuildNumber)'].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, '$(Build.BuildNumber)')].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, '$(Build.BuildNumber)')].roleName" -o tsv`; do echo "purging custom role definition: $i" && $(az role definition delete --name $i || true); done
+ env:
+ ARM_CLIENT_SECRET: $(ARM_CLIENT_SECRET)
diff --git a/.pipelines/deploy-aks-online-standalone.yaml b/.pipelines/deploy-aks-online-standalone.yaml
new file mode 100644
index 00000000..b6471480
--- /dev/null
+++ b/.pipelines/deploy-aks-online-standalone.yaml
@@ -0,0 +1,100 @@
+trigger: none
+
+variables:
+ - group: iac-secure-caf
+ - name: "ARM_PARTNER_ID"
+ value: "f85b2775-ec1d-4fef-949e-bbd6957082af"
+ - name: "ENVIRONMENT"
+ value: "$(Build.BuildNumber)"
+
+stages:
+- stage: deploy_standalone
+ jobs:
+ - job: deploy_standalone
+ displayName: "Deploy Standalone"
+
+ steps:
+ - task: TerraformInstaller@0
+ inputs:
+ terraformVersion: '1.0.3'
+ - task: AzureCLI@2
+ displayName: Deploy Standalone
+ name: deploy_standalone
+ inputs:
+ azureSubscription: $(AZURE_SERVICE_NAME)
+ scriptLocation: inlineScript
+ scriptType: bash
+ inlineScript: |
+ pwd
+ cd enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/
+ configuration_folder=configuration
+ parameter_files=$(find $configuration_folder -not -path "*launchpad*" | grep .tfvars | sed 's/.*/-var-file &/' | xargs)
+ terraform init -upgrade
+ eval terraform apply ${parameter_files} -var tags='{testing_job_id='"$ENVIRONMENT"'}' -auto-approve
+ env:
+ ARM_CLIENT_SECRET: $(ARM_CLIENT_SECRET)
+ - task: AzureCLI@2
+ displayName: Standalone Test
+ name: test
+ inputs:
+ azureSubscription: $(AZURE_SERVICE_NAME)
+ scriptLocation: inlineScript
+ scriptType: bash
+ inlineScript: |
+ pwd
+ cd enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/
+ ls -lta
+ export ARM_SUBSCRIPTION_ID=$(az account show --query id -o tsv)
+ export PREFIX=$(terraform output -json | jq -r '.global_settings.value.prefixes[0]')
+ echo $(terraform output -json | jq -r .aks_clusters_kubeconfig.value.cluster_re1.aks_kubeconfig_admin_cmd) | bash
+
+ cd ../test
+ go mod tidy
+ go test -v shared_services/shared_services_test.go
+ go test -v aks/aks_test.go
+ go test -v flux/flux_test.go
+ env:
+ ARM_CLIENT_SECRET: $(ARM_CLIENT_SECRET)
+ - task: AzureCLI@2
+ displayName: Destroy Standalone
+ name: destroy_standalone
+ inputs:
+ azureSubscription: $(AZURE_SERVICE_NAME)
+ scriptLocation: inlineScript
+ scriptType: bash
+ inlineScript: |
+ ls -lta
+ pwd
+ cd enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone
+ configuration_folder=configuration
+ parameter_files=$(find $configuration_folder -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
+ env:
+ ARM_CLIENT_SECRET: $(ARM_CLIENT_SECRET)
+- stage: purge
+ condition: always()
+ jobs:
+ - job: purge
+ displayName: "Purge"
+ steps:
+ - task: AzureCLI@2
+ displayName: Purge
+ name: destroy_launchpad
+ inputs:
+ azureSubscription: $(AZURE_SERVICE_NAME)
+ scriptLocation: inlineScript
+ scriptType: bash
+ inlineScript: |
+ echo BuildNumber $(Build.BuildNumber)
+ for i in `az monitor diagnostic-settings subscription list -o tsv --query "value[?contains(name, '$(Build.BuildNumber)' )].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, '$(Build.BuildNumber)')].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, '$(Build.BuildNumber)')].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=='$(Build.BuildNumber)'].name" -o tsv`; do az keyvault purge --name $i; done
+ for i in `az group list --query "[?tags.testing_job_id=='$(Build.BuildNumber)'].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, '$(Build.BuildNumber)')].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, '$(Build.BuildNumber)')].roleName" -o tsv`; do echo "purging custom role definition: $i" && $(az role definition delete --name $i || true); done
+ env:
+ ARM_CLIENT_SECRET: $(ARM_CLIENT_SECRET)
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 1b8397b3..c5276a76 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -9,7 +9,7 @@ repos:
# - id: terraform_tflint
# - id: terraform_tfsec
- repo: git://github.com/pre-commit/pre-commit-hooks
- rev: v3.4.0
+ rev: v4.0.1
hooks:
- id: check-merge-conflict
- id: trailing-whitespace
diff --git a/.vscode/settings.json b/.vscode/settings.json
index bc037280..181685b1 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -4,4 +4,4 @@
"editor.tabSize": 2,
"terminal.integrated.scrollback": 8000,
"terminal.integrated.cwd": "/tf/caf",
-}
\ No newline at end of file
+}
diff --git a/enterprise_scale/README.md b/enterprise_scale/README.md
deleted file mode 100644
index e69de29b..00000000
diff --git a/enterprise_scale/construction_sets/README.md b/enterprise_scale/construction_sets/README.md
deleted file mode 100644
index e69de29b..00000000
diff --git a/enterprise_scale/construction_sets/aks/README.md b/enterprise_scale/construction_sets/aks/README.md
deleted file mode 100644
index e69de29b..00000000
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/01-terraform.md b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/01-terraform.md
deleted file mode 100644
index 85f70b3f..00000000
--- a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/01-terraform.md
+++ /dev/null
@@ -1,69 +0,0 @@
-# Deployment of Enterprise-Scale AKS Construction Set
-
-This reference implementation of AKS Secure Baseline Architecture within Enterprise Scale environment is built on CAF Terraform Landing zone framework composition.
-
-The following components will be deployed by the Enterprise-Scale AKS Construction Set. You can review each component as described below:
-
-![aks_enterprise_scale_lz](pictures/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 |
-||
**Identity & Access Management**
||
-| Identity & Access Management | [iam_aad.tfvars](./configuration/iam/iam_aad.tfvars)
[iam_managed_identities.tfvars](./configuration/iam/iam_managed_identities.tfvars)
[iam_role_mappings.tfvars](./configuration/iam/iam_role_mappings.tfvars)| AAD admin group, User Managed Identities & Role Assignments |
-||**Gateway**
||
-| Application Gateway | [agw.tfvars](./configuration/agw/agw.tfvars)
[agw_application.tfvars](./configuration/agw/agw_application.tfvars)
| 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 |
-||**Networking**
||
-| Virtual networks | [networking.tfvars](./configuration/networking/networking.tfvars)
[peerings.tfvars](./configuration/networking/peerings.tfvars)
[nsg.tfvars](./configuration/networking/nsg.tfvars)
[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)
[firewall_application_rule_collection_definition.tfvars](./configuration/networking/firewall_application_rule_collection_definition.tfvars)
[firewall_network_rule_collection_definition.tfvars](./configuration/networking/firewall_network_rule_collection_definition.tfvars)
[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 |
-||**Security & Monitoring**
||
-| Azure Key Vault| [keyvaults.tfvars](./configuration/keyvault/keyvaults.tfvars)
[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)
[log_analytics.tfvars](./configuration/monitor/log_analytics.tfvars) | Diagnostics settings, Log Analytics Workspace for AKS logs & Prometheus metrics |
-||**Bastion**
||
-| Azure Bastion (OPTIONAL) | [bastion.tfvars](./configuration/bastion/bastion.ignore) | Azure Bastion Host & Windows VM to view aspnetsample website internally. |
-
-
-
-## Deployment
-
-```bash
-# Script to execute from bash shell
-
-# Login to your Azure Active Directory tenant
-az login -t {TENANTNID}
-
-# Make sure you are using the right subscription
-az account show -o table
-
-# If you are not in the correct subscription, change it substituting SUBSCRIPTIONID with the proper subscription id
-az account set --subscription {SUBSCRIPTIONID}
-
-# If you are running in Azure Cloud Shell, you need to run the following additional command:
-export TF_VAR_logged_user_objectId=$(az ad signed-in-user show --query objectId -o tsv)
-
-# Go to the AKS construction set folder
-cd caf-terraform-landingzones-starter/enterprise_scale/construction_sets/aks
-
-configuration_folder=online/aks_secure_baseline/configuration
-
-# Define the configuration files to apply, all tfvars files within the above folder recursively
-parameter_files=$(find $configuration_folder | grep .tfvars | sed 's/.*/-var-file &/' | xargs)
-
-# Load the CAF module and related providers
-terraform init -upgrade
-
-# Trigger the deployment of the resources
-eval terraform apply ${parameter_files}
-
-```
-
-You are done with deployment of AKS environment, next step is to deploy the application and reference components.
-
-## Next step
-
-:arrow_forward: [Deploy sample workload into AKS](./02-aks.md)
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/README.md b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/README.md
index cdfbbb4c..8460f323 100644
--- a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/README.md
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/README.md
@@ -33,77 +33,12 @@ az policy assignment list --disable-scope-strict-match
az policy assignment list --disable-scope-strict-match --scope {RESOURCEID}
```
-## Prerequisites
-
-### Supported run environment
-
-In order to deploy the AKS Construction set, you can use the following options:
-
-- [Windows Subsystem for Linux](https://docs.microsoft.com/windows/wsl/about#what-is-wsl-2)
-- [Azure Cloud Shell](https://shell.azure.com)
-- Linux Bash Shell
-- MacOS Shell
-- GitHub CodeSpace
-
-### Configuration steps
-
-If you opt-in to setup a shell on your machine, there are required access and tooling you'll need in order to accomplish this. Follow the instructions below and on the subsequent pages so that you can get your environment ready to proceed with the AKS cluster creation.
-
-1. An Azure subscription. If you don't have an Azure subscription, you can create a [free account](https://azure.microsoft.com/free).
-
- > :warning: The user or service principal initiating the deployment process _must_ have the following minimal set of Azure Role-Based Access Control (RBAC) roles:
- >
- > * [Contributor role](https://docs.microsoft.com/azure/role-based-access-control/built-in-roles#contributor) is _required_ at the subscription level to have the ability to create resource groups and perform deployments.
- > * [User Access Administrator role](https://docs.microsoft.com/azure/role-based-access-control/built-in-roles#user-access-administrator) is _required_ at the subscription level since you'll be granting least-privilege RBAC access to managed identities.
- > * One such example is detailed in the [Container Insights documentation](https://docs.microsoft.com/azure/azure-monitor/insights/container-insights-troubleshoot#authorization-error-during-onboarding-or-update-operation).
-
-2. An Azure AD tenant to associate your Kubernetes RBAC configuration to.
-
- > :warning: The user or service principal initiating the deployment process _must_ have the following minimal set of Azure AD permissions assigned:
- >
- > * Azure AD [User Administrator](https://docs.microsoft.com/azure/active-directory/users-groups-roles/directory-assign-admin-roles#user-administrator-permissions) is _required_ to create a "break glass" AKS admin Active Directory Security Group and User. Alternatively, you could get your Azure AD admin to create this for you when instructed to do so.
- > * If you are not part of the User Administrator group in the tenant associated to your Azure subscription, please consider [creating a new tenant](https://docs.microsoft.com/azure/active-directory/fundamentals/active-directory-access-create-new-tenant#create-a-new-tenant-for-your-organization) to use while evaluating this implementation.
-
-3. If you opt for Azure Cloud Shell, you don't need to complete those steps and can jump on the next section (step 4). On Windows, you can use the Ubuntu on [Windows Subsystem for Linux](https://docs.microsoft.com/windows/wsl/about#what-is-wsl-2) to run Bash. Once your bash shell is up you will need to install these prerequisites.
-
- Latest [Azure CLI installed](https://docs.microsoft.com/cli/azure/install-azure-cli?view=azure-cli-latest)
-
- ```bash
- sudo apt install azure-cli
- ```
-
- Terrafrom (Ubuntu) : For more information visit [here](https://learn.hashicorp.com/tutorials/terraform/install-cli)
-
- ```bash
- curl -fsSL https://apt.releases.hashicorp.com/gpg | sudo apt-key add -
- sudo apt-add-repository "deb [arch=amd64] https://apt.releases.hashicorp.com $(lsb_release -cs) main"
- sudo apt-get update && sudo apt-get install terraform
- ```
-
- jq : For more information visit [here](https://stedolan.github.io/jq/download/)
-
- ```bash
- sudo apt install jq
- ```
-
- kubectl: For more information visit [here](https://kubernetes.io/docs/tasks/tools/install-kubectl/)
-
- ```bash
- # kubectl:
- curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
- sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl
- ```
-
-4. Clone/download this repo locally, or even better fork this repository.
-
- > :twisted_rightwards_arrows: If you have forked this reference implementation repo, you'll be able to customize some of the files and commands for a more personalized experience; also ensure references to repos mentioned are updated to use your own (e.g. the following `GITHUB_REPO`).
+# Next step
- ```bash
- export GITHUB_REPO=https://github.com/Azure/caf-terraform-landingzones-starter.git
- git clone $GITHUB_REPO
- ```
+## Landing Zone
+:arrow_forward: [Deploy infrastructures using CAF Terraform Landing zone](landingzone)
-# Next step
+## Standalone
-:arrow_forward: [Deploy infrastructures using Terraform](./01-terraform.md)
+:arrow_forward: [Deploy infrastructures using Terraform CLI](standalone)
\ No newline at end of file
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/cluster-baseline-settings/aad-pod-identity.yaml b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/cluster-baseline-settings/aad-pod-identity.yaml
index c98868bc..d25228f8 100644
--- a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/cluster-baseline-settings/aad-pod-identity.yaml
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/cluster-baseline-settings/aad-pod-identity.yaml
@@ -1,127 +1,388 @@
-apiVersion: apiextensions.k8s.io/v1beta1
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ name: aad-pod-id-nmi-service-account
+ namespace: cluster-baseline-settings
+---
+apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
+ annotations:
+ api-approved.kubernetes.io: unapproved
+ controller-gen.kubebuilder.io/version: v0.5.0
name: azureassignedidentities.aadpodidentity.k8s.io
- labels:
- app.kubernetes.io/name: aad-pod-identity
- app.kubernetes.io/instance: aad-pod-identity
spec:
group: aadpodidentity.k8s.io
- version: v1
names:
kind: AzureAssignedIdentity
+ listKind: AzureAssignedIdentityList
plural: azureassignedidentities
+ singular: azureassignedidentity
scope: Namespaced
+ versions:
+ - name: v1
+ schema:
+ openAPIV3Schema:
+ description: AzureAssignedIdentity contains the identity <-> pod mapping which is matched.
+ properties:
+ apiVersion:
+ description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
+ type: string
+ kind:
+ description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
+ type: string
+ metadata:
+ type: object
+ spec:
+ description: AzureAssignedIdentitySpec contains the relationship between an AzureIdentity and an AzureIdentityBinding.
+ properties:
+ azureBindingRef:
+ description: AzureIdentityBinding brings together the spec of matching pods and the identity which they can use.
+ properties:
+ apiVersion:
+ description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
+ type: string
+ kind:
+ description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
+ type: string
+ metadata:
+ type: object
+ spec:
+ description: AzureIdentityBindingSpec matches the pod with the Identity. Used to indicate the potential matches to look for between the pod/deployment and the identities present.
+ properties:
+ azureIdentity:
+ type: string
+ metadata:
+ type: object
+ selector:
+ type: string
+ weight:
+ description: Weight is used to figure out which of the matching identities would be selected.
+ type: integer
+ type: object
+ status:
+ description: AzureIdentityBindingStatus contains the status of an AzureIdentityBinding.
+ properties:
+ availableReplicas:
+ format: int32
+ type: integer
+ metadata:
+ type: object
+ type: object
+ type: object
+ x-kubernetes-embedded-resource: true
+ azureIdentityRef:
+ description: AzureIdentity is the specification of the identity data structure.
+ properties:
+ apiVersion:
+ description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
+ type: string
+ kind:
+ description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
+ type: string
+ metadata:
+ type: object
+ spec:
+ description: AzureIdentitySpec describes the credential specifications of an identity on Azure.
+ properties:
+ adEndpoint:
+ type: string
+ adResourceID:
+ description: For service principal. Option param for specifying the AD details.
+ type: string
+ auxiliaryTenantIDs:
+ description: Service principal auxiliary tenant ids
+ items:
+ type: string
+ nullable: true
+ type: array
+ clientID:
+ description: Both User Assigned MSI and SP can use this field.
+ type: string
+ clientPassword:
+ description: Used for service principal
+ properties:
+ name:
+ description: Name is unique within a namespace to reference a secret resource.
+ type: string
+ namespace:
+ description: Namespace defines the space within which the secret name must be unique.
+ type: string
+ type: object
+ metadata:
+ type: object
+ replicas:
+ format: int32
+ nullable: true
+ type: integer
+ resourceID:
+ description: User assigned MSI resource id.
+ type: string
+ tenantID:
+ description: Service principal primary tenant id.
+ type: string
+ type:
+ description: UserAssignedMSI or Service Principal
+ type: integer
+ type: object
+ status:
+ description: AzureIdentityStatus contains the replica status of the resource.
+ properties:
+ availableReplicas:
+ format: int32
+ type: integer
+ metadata:
+ type: object
+ type: object
+ type: object
+ x-kubernetes-embedded-resource: true
+ metadata:
+ type: object
+ nodename:
+ type: string
+ pod:
+ type: string
+ podNamespace:
+ type: string
+ replicas:
+ format: int32
+ nullable: true
+ type: integer
+ type: object
+ status:
+ description: AzureAssignedIdentityStatus contains the replica status of the resource.
+ properties:
+ availableReplicas:
+ format: int32
+ type: integer
+ metadata:
+ type: object
+ status:
+ type: string
+ type: object
+ type: object
+ served: true
+ storage: true
+status:
+ acceptedNames:
+ kind: ""
+ plural: ""
+ conditions: []
+ storedVersions: []
---
-apiVersion: apiextensions.k8s.io/v1beta1
+apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
+ annotations:
+ api-approved.kubernetes.io: unapproved
+ controller-gen.kubebuilder.io/version: v0.5.0
name: azureidentities.aadpodidentity.k8s.io
- labels:
- app.kubernetes.io/name: aad-pod-identity
- app.kubernetes.io/instance: aad-pod-identity
spec:
group: aadpodidentity.k8s.io
- version: v1
names:
kind: AzureIdentity
- singular: azureidentity
+ listKind: AzureIdentityList
plural: azureidentities
+ singular: azureidentity
scope: Namespaced
+ versions:
+ - name: v1
+ schema:
+ openAPIV3Schema:
+ description: AzureIdentity is the specification of the identity data structure.
+ properties:
+ apiVersion:
+ description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
+ type: string
+ kind:
+ description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
+ type: string
+ metadata:
+ type: object
+ spec:
+ description: AzureIdentitySpec describes the credential specifications of an identity on Azure.
+ properties:
+ adEndpoint:
+ type: string
+ adResourceID:
+ description: For service principal. Option param for specifying the AD details.
+ type: string
+ auxiliaryTenantIDs:
+ description: Service principal auxiliary tenant ids
+ items:
+ type: string
+ nullable: true
+ type: array
+ clientID:
+ description: Both User Assigned MSI and SP can use this field.
+ type: string
+ clientPassword:
+ description: Used for service principal
+ properties:
+ name:
+ description: Name is unique within a namespace to reference a secret resource.
+ type: string
+ namespace:
+ description: Namespace defines the space within which the secret name must be unique.
+ type: string
+ type: object
+ metadata:
+ type: object
+ replicas:
+ format: int32
+ nullable: true
+ type: integer
+ resourceID:
+ description: User assigned MSI resource id.
+ type: string
+ tenantID:
+ description: Service principal primary tenant id.
+ type: string
+ type:
+ description: UserAssignedMSI or Service Principal
+ type: integer
+ type: object
+ status:
+ description: AzureIdentityStatus contains the replica status of the resource.
+ properties:
+ availableReplicas:
+ format: int32
+ type: integer
+ metadata:
+ type: object
+ type: object
+ type: object
+ served: true
+ storage: true
+status:
+ acceptedNames:
+ kind: ""
+ plural: ""
+ conditions: []
+ storedVersions: []
---
-apiVersion: apiextensions.k8s.io/v1beta1
+apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
+ annotations:
+ api-approved.kubernetes.io: unapproved
+ controller-gen.kubebuilder.io/version: v0.5.0
name: azureidentitybindings.aadpodidentity.k8s.io
- labels:
- app.kubernetes.io/name: aad-pod-identity
- app.kubernetes.io/instance: aad-pod-identity
spec:
group: aadpodidentity.k8s.io
- version: v1
names:
kind: AzureIdentityBinding
+ listKind: AzureIdentityBindingList
plural: azureidentitybindings
+ singular: azureidentitybinding
scope: Namespaced
+ versions:
+ - name: v1
+ schema:
+ openAPIV3Schema:
+ description: AzureIdentityBinding brings together the spec of matching pods and the identity which they can use.
+ properties:
+ apiVersion:
+ description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
+ type: string
+ kind:
+ description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
+ type: string
+ metadata:
+ type: object
+ spec:
+ description: AzureIdentityBindingSpec matches the pod with the Identity. Used to indicate the potential matches to look for between the pod/deployment and the identities present.
+ properties:
+ azureIdentity:
+ type: string
+ metadata:
+ type: object
+ selector:
+ type: string
+ weight:
+ description: Weight is used to figure out which of the matching identities would be selected.
+ type: integer
+ type: object
+ status:
+ description: AzureIdentityBindingStatus contains the status of an AzureIdentityBinding.
+ properties:
+ availableReplicas:
+ format: int32
+ type: integer
+ metadata:
+ type: object
+ type: object
+ type: object
+ served: true
+ storage: true
+status:
+ acceptedNames:
+ kind: ""
+ plural: ""
+ conditions: []
+ storedVersions: []
---
-apiVersion: apiextensions.k8s.io/v1beta1
+apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
+ annotations:
+ api-approved.kubernetes.io: unapproved
+ controller-gen.kubebuilder.io/version: v0.5.0
name: azurepodidentityexceptions.aadpodidentity.k8s.io
- labels:
- app.kubernetes.io/name: aad-pod-identity
- app.kubernetes.io/instance: aad-pod-identity
spec:
group: aadpodidentity.k8s.io
- version: v1
names:
kind: AzurePodIdentityException
- singular: azurepodidentityexception
+ listKind: AzurePodIdentityExceptionList
plural: azurepodidentityexceptions
+ singular: azurepodidentityexception
scope: Namespaced
----
-apiVersion: v1
-kind: ServiceAccount
-metadata:
- name: aad-pod-identity-mic
- namespace: cluster-baseline-settings
- labels:
- app.kubernetes.io/name: aad-pod-identity
- app.kubernetes.io/instance: aad-pod-identity
- app.kubernetes.io/component: mic
----
-apiVersion: v1
-kind: ServiceAccount
-metadata:
- name: aad-pod-identity-nmi
- namespace: cluster-baseline-settings
- labels:
- app.kubernetes.io/name: aad-pod-identity
- app.kubernetes.io/instance: aad-pod-identity
- app.kubernetes.io/component: nmi
+ versions:
+ - name: v1
+ schema:
+ openAPIV3Schema:
+ description: AzurePodIdentityException contains the pod selectors for all pods that don't require NMI to process and request token on their behalf.
+ properties:
+ apiVersion:
+ description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
+ type: string
+ kind:
+ description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
+ type: string
+ metadata:
+ type: object
+ spec:
+ description: AzurePodIdentityExceptionSpec matches pods with the selector defined. If request originates from a pod that matches the selector, nmi will proxy the request and send response back without any validation.
+ properties:
+ metadata:
+ type: object
+ podLabels:
+ additionalProperties:
+ type: string
+ type: object
+ type: object
+ status:
+ description: AzurePodIdentityExceptionStatus contains the status of an AzurePodIdentityException.
+ properties:
+ metadata:
+ type: object
+ status:
+ type: string
+ type: object
+ type: object
+ served: true
+ storage: true
+status:
+ acceptedNames:
+ kind: ""
+ plural: ""
+ conditions: []
+ storedVersions: []
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
- name: aad-pod-identity-mic
- labels:
- app.kubernetes.io/name: aad-pod-identity
- app.kubernetes.io/instance: aad-pod-identity
- app.kubernetes.io/component: mic
-rules:
-- apiGroups: ["apiextensions.k8s.io"]
- resources: ["customresourcedefinitions"]
- verbs: ["*"]
-- apiGroups: [""]
- resources: ["pods", "nodes"]
- verbs: [ "list", "watch" ]
-- apiGroups: [""]
- resources: ["events"]
- verbs: ["create", "patch"]
-- apiGroups: [""]
- resources: ["configmaps"]
- verbs: ["get", "create", "update"]
-- apiGroups: [""]
- resources: ["endpoints"]
- verbs: [ "create", "get", "update"]
-- apiGroups: ["aadpodidentity.k8s.io"]
- resources: ["azureidentitybindings", "azureidentities"]
- verbs: ["get", "list", "watch", "post", "update"]
-- apiGroups: ["aadpodidentity.k8s.io"]
- resources: ["azurepodidentityexceptions"]
- verbs: ["list", "update"]
-- apiGroups: ["aadpodidentity.k8s.io"]
- resources: ["azureassignedidentities"]
- verbs: ["*"]
----
-apiVersion: rbac.authorization.k8s.io/v1
-kind: ClusterRole
-metadata:
- name: aad-pod-identity-nmi
- labels:
- app.kubernetes.io/name: aad-pod-identity
- app.kubernetes.io/instance: aad-pod-identity
- app.kubernetes.io/component: nmi
+ name: aad-pod-id-nmi-role
rules:
- apiGroups: ["apiextensions.k8s.io"]
resources: ["customresourcedefinitions"]
@@ -142,67 +403,41 @@ rules:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
- name: aad-pod-identity-mic
+ name: aad-pod-id-nmi-binding
labels:
- app.kubernetes.io/name: aad-pod-identity
- app.kubernetes.io/instance: aad-pod-identity
- app.kubernetes.io/component: mic
+ k8s-app: aad-pod-id-nmi-binding
subjects:
- kind: ServiceAccount
- name: aad-pod-identity-mic
+ name: aad-pod-id-nmi-service-account
namespace: cluster-baseline-settings
roleRef:
kind: ClusterRole
- name: aad-pod-identity-mic
- apiGroup: rbac.authorization.k8s.io
----
-apiVersion: rbac.authorization.k8s.io/v1
-kind: ClusterRoleBinding
-metadata:
- name: aad-pod-identity-nmi
- labels:
- app.kubernetes.io/name: aad-pod-identity
- app.kubernetes.io/instance: aad-pod-identity
- app.kubernetes.io/component: nmi
-subjects:
-- kind: ServiceAccount
- name: aad-pod-identity-nmi
- namespace: cluster-baseline-settings
-roleRef:
- kind: ClusterRole
- name: aad-pod-identity-nmi
+ name: aad-pod-id-nmi-role
apiGroup: rbac.authorization.k8s.io
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
- name: aad-pod-identity-nmi
- namespace: cluster-baseline-settings
labels:
- app.kubernetes.io/name: aad-pod-identity
- app.kubernetes.io/instance: aad-pod-identity
- app.kubernetes.io/component: nmi
+ component: nmi
tier: node
- annotations:
- description: Deploy components for aad-pod-identity
+ k8s-app: aad-pod-id
+ name: nmi
+ namespace: cluster-baseline-settings
spec:
updateStrategy:
type: RollingUpdate
selector:
matchLabels:
- app.kubernetes.io/name: aad-pod-identity
- app.kubernetes.io/instance: aad-pod-identity
- app.kubernetes.io/component: nmi
+ component: nmi
tier: node
template:
metadata:
labels:
- app.kubernetes.io/name: aad-pod-identity
- app.kubernetes.io/instance: aad-pod-identity
- app.kubernetes.io/component: nmi
+ component: nmi
tier: node
spec:
- serviceAccountName: aad-pod-identity-nmi
+ serviceAccountName: aad-pod-id-nmi-service-account
hostNetwork: true
dnsPolicy: ClusterFirstWithHostNet
volumes:
@@ -210,31 +445,46 @@ spec:
path: /run/xtables.lock
type: FileOrCreate
name: iptableslock
- - hostPath:
+ - name: kubelet-config
+ hostPath:
path: /etc/default/kubelet
- name: kubelet-config
+ type: FileOrCreate
containers:
- name: nmi
- image: "mcr.microsoft.com/oss/azure/aad-pod-identity/nmi:v1.7.0"
- imagePullPolicy: Always
+ image: "mcr.microsoft.com/oss/azure/aad-pod-identity/nmi:v1.8.0"
args:
- "--node=$(NODE_NAME)"
- "--http-probe-port=8085"
env:
+ - name: HOST_IP
+ valueFrom:
+ fieldRef:
+ fieldPath: status.podIP
- name: NODE_NAME
valueFrom:
fieldRef:
fieldPath: spec.nodeName
+ resources:
+ limits:
+ cpu: 200m
+ memory: 512Mi
+ requests:
+ cpu: 100m
+ memory: 256Mi
securityContext:
runAsUser: 0
capabilities:
+ drop:
+ - ALL
add:
+ - DAC_READ_SEARCH
- NET_ADMIN
+ - NET_RAW
volumeMounts:
- mountPath: /run/xtables.lock
name: iptableslock
- - mountPath: /etc/default/kubelet
- name: kubelet-config
+ - name: kubelet-config
+ mountPath: /etc/default/kubelet
readOnly: true
livenessProbe:
httpGet:
@@ -242,47 +492,85 @@ spec:
port: 8085
initialDelaySeconds: 10
periodSeconds: 5
- resources:
- limits:
- cpu: 200m
- memory: 512Mi
- requests:
- cpu: 100m
- memory: 256Mi
nodeSelector:
kubernetes.io/os: linux
agentpool: npuser01
---
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ name: aad-pod-id-mic-service-account
+ namespace: cluster-baseline-settings
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+ name: aad-pod-id-mic-role
+rules:
+- apiGroups: ["apiextensions.k8s.io"]
+ resources: ["customresourcedefinitions"]
+ verbs: ["*"]
+- apiGroups: [""]
+ resources: ["pods", "nodes"]
+ verbs: [ "list", "watch" ]
+- apiGroups: [""]
+ resources: ["events"]
+ verbs: ["create", "patch"]
+- apiGroups: [""]
+ resources: ["configmaps"]
+ verbs: ["get", "create", "update"]
+- apiGroups: [""]
+ resources: ["endpoints"]
+ verbs: ["create", "get","update"]
+- apiGroups: ["aadpodidentity.k8s.io"]
+ resources: ["azureidentitybindings", "azureidentities"]
+ verbs: ["get", "list", "watch", "post", "update"]
+- apiGroups: ["aadpodidentity.k8s.io"]
+ resources: ["azurepodidentityexceptions"]
+ verbs: ["list", "update"]
+- apiGroups: ["aadpodidentity.k8s.io"]
+ resources: ["azureassignedidentities"]
+ verbs: ["*"]
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+ name: aad-pod-id-mic-binding
+ labels:
+ k8s-app: aad-pod-id-mic-binding
+subjects:
+- kind: ServiceAccount
+ name: aad-pod-id-mic-service-account
+ namespace: cluster-baseline-settings
+roleRef:
+ kind: ClusterRole
+ name: aad-pod-id-mic-role
+ apiGroup: rbac.authorization.k8s.io
+---
apiVersion: apps/v1
kind: Deployment
metadata:
- name: aad-pod-identity-mic
- namespace: cluster-baseline-settings
labels:
- app.kubernetes.io/name: aad-pod-identity
- app.kubernetes.io/instance: aad-pod-identity
- app.kubernetes.io/component: mic
- annotations:
- description: Deploy components for aad-pod-identity
+ component: mic
+ k8s-app: aad-pod-id
+ name: mic
+ namespace: cluster-baseline-settings
spec:
replicas: 2
selector:
matchLabels:
- app.kubernetes.io/name: aad-pod-identity
- app.kubernetes.io/instance: aad-pod-identity
- app.kubernetes.io/component: mic
+ component: mic
+ app: mic
template:
metadata:
labels:
- app.kubernetes.io/name: aad-pod-identity
- app.kubernetes.io/instance: aad-pod-identity
- app.kubernetes.io/component: mic
+ component: mic
+ app: mic
spec:
- serviceAccountName: aad-pod-identity-mic
+ serviceAccountName: aad-pod-id-mic-service-account
containers:
- name: mic
- image: "mcr.microsoft.com/oss/azure/aad-pod-identity/mic:v1.7.0"
- imagePullPolicy: Always
+ image: "mcr.microsoft.com/oss/azure/aad-pod-identity/mic:v1.8.0"
args:
- "--cloudconfig=/etc/kubernetes/azure.json"
- "--logtostderr"
@@ -293,6 +581,13 @@ spec:
valueFrom:
fieldRef:
fieldPath: metadata.namespace
+ resources:
+ limits:
+ cpu: 200m
+ memory: 1024Mi
+ requests:
+ cpu: 100m
+ memory: 256Mi
volumeMounts:
- name: k8s-azure-file
mountPath: /etc/kubernetes/azure.json
@@ -303,13 +598,6 @@ spec:
port: 8080
initialDelaySeconds: 10
periodSeconds: 5
- resources:
- limits:
- cpu: 200m
- memory: 1024Mi
- requests:
- cpu: 100m
- memory: 256Mi
volumes:
- name: k8s-azure-file
hostPath:
@@ -325,9 +613,8 @@ metadata:
namespace: cluster-baseline-settings
spec:
podLabels:
- app.kubernetes.io/name: aad-pod-identity
- app.kubernetes.io/instance: aad-pod-identity
- app.kubernetes.io/component: mic
+ app: mic
+ component: mic
---
apiVersion: aadpodidentity.k8s.io/v1
kind: AzurePodIdentityException
@@ -363,4 +650,4 @@ metadata:
namespace: kube-system
spec:
podLabels:
- rsName: omsagent-rs
+ rsName: omsagent-rs
\ No newline at end of file
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/cluster-baseline-settings/flux.yaml b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/cluster-baseline-settings/flux.yaml
deleted file mode 100644
index 3dfa94f3..00000000
--- a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/cluster-baseline-settings/flux.yaml
+++ /dev/null
@@ -1,186 +0,0 @@
-kind: Namespace
-apiVersion: v1
-metadata:
- name: cluster-baseline-settings
----
-apiVersion: v1
-kind: ServiceAccount
-metadata:
- labels:
- app.kubernetes.io/name: flux
- name: flux
- namespace: cluster-baseline-settings
----
-kind: ClusterRole
-apiVersion: rbac.authorization.k8s.io/v1beta1
-metadata:
- name: flux
- labels:
- app.kubernetes.io/name: flux
-rules:
- - apiGroups: ['*']
- resources: ['*']
- verbs: ['*']
- - nonResourceURLs: ['*']
- verbs: ['*']
----
-kind: ClusterRoleBinding
-apiVersion: rbac.authorization.k8s.io/v1beta1
-metadata:
- name: flux
- labels:
- app.kubernetes.io/name: flux
-roleRef:
- apiGroup: rbac.authorization.k8s.io
- kind: ClusterRole
- name: flux
-subjects:
- - kind: ServiceAccount
- name: flux
- namespace: cluster-baseline-settings
----
-apiVersion: apps/v1
-kind: Deployment
-metadata:
- name: flux
- namespace: cluster-baseline-settings
-spec:
- replicas: 1
- selector:
- matchLabels:
- app.kubernetes.io/name: flux
- strategy:
- type: Recreate
- template:
- metadata:
- annotations:
- prometheus.io/port: "3031"
- labels:
- app.kubernetes.io/name: flux
- spec:
- nodeSelector:
- kubernetes.io/os: linux
- agentpool: npuser01
- serviceAccountName: flux
- volumes:
- - name: git-key
- secret:
- secretName: flux-git-deploy
- containers:
- - name: flux
- # PRODUCTION READINESS CHANGE REQUIRED
- # This image should be sourced from a non-public container registry, such as the
- # one deployed along side of this reference implementation.
- # az acr import --source docker.io/fluxcd/flux:1.19.0 -n
- # and then set this to
- # image: .azurecr.io/fluxcd/flux:1.19.0
- image: docker.io/fluxcd/flux:1.21.1
- imagePullPolicy: IfNotPresent
- securityContext:
- capabilities:
- drop:
- - ALL
- allowPrivilegeEscalation: false
- # create folder in the root fs when cloning repos
- readOnlyRootFilesystem: false
- # access to root folder like /.kube/config
- runAsNonRoot: false
- volumeMounts:
- - name: git-key
- mountPath: /etc/fluxd/ssh
- readOnly: true
- resources:
- requests:
- cpu: 50m
- memory: 64Mi
- ports:
- - containerPort: 3030
- livenessProbe:
- httpGet:
- port: 3030
- path: /api/flux/v6/identity.pub
- initialDelaySeconds: 5
- timeoutSeconds: 5
- readinessProbe:
- httpGet:
- port: 3030
- path: /api/flux/v6/identity.pub
- initialDelaySeconds: 5
- timeoutSeconds: 5
- args:
- - --git-url=https://github.com/Azure/caf-terraform-landingzones-starter.git
- - --git-branch=starter
- - --git-path=enterprise_scale/construction_sets/aks/online/aks_secure_baseline/cluster-baseline-settings
- # this configuration prevents flux from syncing changes from your cluster to the git repo. If two way sync is required, please take a look at https://docs.fluxcd.io/en/1.19.0/tutorials/get-started/#giving-write-access
- - --git-readonly
- - --sync-state=secret
- - --listen-metrics=:3031
- - --git-timeout=5m
- - --registry-disable-scanning=true
----
-# This secret is ok to be initialized as empty since Flux annotates the
-# Kubernetes Secret object with flux.weave.works/sync-hwm:
-# as a way to store the latest commit applied to the cluster and later on
-# compare with to confirm wether it is in sync or not.
-apiVersion: v1
-kind: Secret
-metadata:
- name: flux-git-deploy
- namespace: cluster-baseline-settings
-type: Opaque
----
-apiVersion: apps/v1
-kind: Deployment
-metadata:
- name: memcached
- namespace: cluster-baseline-settings
-spec:
- replicas: 1
- selector:
- matchLabels:
- app.kubernetes.io/name: memcached
- template:
- metadata:
- labels:
- app.kubernetes.io/name: memcached
- spec:
- nodeSelector:
- kubernetes.io/os: linux
- agentpool: npuser01
- containers:
- - name: memcached
- # PRODUCTION READINESS CHANGE REQUIRED
- # This image should be sourced from a non-public container registry, such as the
- # one deployed along side of this reference implementation.
- # az acr import --source docker.io/library/memcached:1.5.20 -n
- # and then set this to
- # image: .azurecr.io/library/memcached:1.5.20
- image: library/memcached:1.5.20
- imagePullPolicy: IfNotPresent
- resources:
- requests:
- memory: 512Mi
- args:
- - -m 512
- - -I 5m # Maximum size for one item
- - -p 11211 # Default port
- # - -vv # Uncomment to get logs of each request and response.
- ports:
- - name: clients
- containerPort: 11211
- securityContext:
- runAsUser: 11211
- runAsGroup: 11211
- allowPrivilegeEscalation: false
----
-apiVersion: v1
-kind: Service
-metadata:
- name: memcached
- namespace: cluster-baseline-settings
-spec:
- ports:
- - name: memcached
- port: 11211
- selector:
- app.kubernetes.io/name: memcached
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/cluster-baseline-settings/flux/flux.yaml b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/cluster-baseline-settings/flux/flux.yaml
new file mode 100644
index 00000000..db3bff06
--- /dev/null
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/cluster-baseline-settings/flux/flux.yaml
@@ -0,0 +1,12 @@
+apiVersion: kustomize.toolkit.fluxcd.io/v1beta1
+kind: Kustomization
+metadata:
+ name: cluster-baseline-settings
+ namespace: flux-system
+spec:
+ interval: 1m
+ path: ./enterprise_scale/construction_sets/aks/online/aks_secure_baseline/cluster-baseline-settings
+ prune: true
+ sourceRef:
+ kind: GitRepository
+ name: flux-system
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/cluster-baseline-settings/kured-1.4.0-dockerhub.yaml b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/cluster-baseline-settings/kured-1.4.0-dockerhub.yaml
deleted file mode 100644
index a0f855d0..00000000
--- a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/cluster-baseline-settings/kured-1.4.0-dockerhub.yaml
+++ /dev/null
@@ -1,109 +0,0 @@
-# https://github.com/weaveworks/kured/releases/download/1.4.0/kured-1.4.0-dockerhub.yaml
----
-apiVersion: rbac.authorization.k8s.io/v1
-kind: ClusterRole
-metadata:
- name: kured
-rules:
- - apiGroups: [""]
- resources: ["nodes"]
- verbs: ["get", "patch"]
- - apiGroups: [""]
- resources: ["pods"]
- verbs: ["list", "delete", "get"]
- - apiGroups: ["apps"]
- resources: ["daemonsets"]
- verbs: ["get"]
- - apiGroups: [""]
- resources: ["pods/eviction"]
- verbs: ["create"]
----
-apiVersion: rbac.authorization.k8s.io/v1
-kind: ClusterRoleBinding
-metadata:
- name: kured
-roleRef:
- apiGroup: rbac.authorization.k8s.io
- kind: ClusterRole
- name: kured
-subjects:
- - kind: ServiceAccount
- name: kured
- namespace: cluster-baseline-settings
----
-apiVersion: rbac.authorization.k8s.io/v1
-kind: Role
-metadata:
- namespace: cluster-baseline-settings
- name: kured
-rules:
- - apiGroups: ["apps"]
- resources: ["daemonsets"]
- resourceNames: ["kured"]
- verbs: ["update"]
----
-apiVersion: rbac.authorization.k8s.io/v1
-kind: RoleBinding
-metadata:
- namespace: cluster-baseline-settings
- name: kured
-subjects:
- - kind: ServiceAccount
- namespace: cluster-baseline-settings
- name: kured
-roleRef:
- apiGroup: rbac.authorization.k8s.io
- kind: Role
- name: kured
----
-apiVersion: v1
-kind: ServiceAccount
-metadata:
- name: kured
- namespace: cluster-baseline-settings
----
-apiVersion: apps/v1
-kind: DaemonSet
-metadata:
- name: kured
- namespace: cluster-baseline-settings
-spec:
- selector:
- matchLabels:
- name: kured
- updateStrategy:
- type: RollingUpdate
- template:
- metadata:
- labels:
- name: kured
- annotations:
- prometheus.io/scrape: "true"
- prometheus.io/port: "8080"
- spec:
- serviceAccountName: kured
- tolerations:
- - key: node-role.kubernetes.io/master
- effect: NoSchedule
- hostPID: true
- restartPolicy: Always
- containers:
- - name: kured
- # PRODUCTION READINESS CHANGE REQUIRED
- # This image should be sourced from a non-public container registry, such as the
- # one deployed along side of this reference implementation.
- # az acr import --source docker.io/weaveworks/kured:1.4.0 -n
- # and then set this to
- # image: .azurecr.io/weaveworks/kured:1.4.0
- image: docker.io/weaveworks/kured:1.4.0
- imagePullPolicy: IfNotPresent
- securityContext:
- privileged: true
- env:
- - name: KURED_NODE_ID
- valueFrom:
- fieldRef:
- fieldPath: spec.nodeName
- command:
- - /usr/bin/kured
- - --ds-namespace=cluster-baseline-settings
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/cluster-baseline-settings/settings-namespace.yaml b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/cluster-baseline-settings/settings-namespace.yaml
new file mode 100644
index 00000000..0fb8e0f4
--- /dev/null
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/cluster-baseline-settings/settings-namespace.yaml
@@ -0,0 +1,4 @@
+kind: Namespace
+apiVersion: v1
+metadata:
+ name: cluster-baseline-settings
\ No newline at end of file
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/README.md b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/README.md
new file mode 100644
index 00000000..101ea6cc
--- /dev/null
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/README.md
@@ -0,0 +1,116 @@
+# Deployment steps
+
+NOTE: before proceeding, owner of the subscription is required.
+
+## Login the Azure AD Tenant
+
+Make sure either VSCode is opened in Container or the below commands are run within the Rover container
+
+```bash
+TENANT_ID=
+SUB_ID=
+rover login -t $TENANT_ID -s $SUB_ID
+```
+
+## Prerequisites
+
+```bash
+git clone --branch azure_devops_v1 https://github.com/Azure/caf-terraform-landingzones.git /tf/caf/landingzones
+```
+
+## Level 0
+
+### Launchpad
+Set-up the launchpads for level0 to level4
+
+```bash
+caf_env="es-aks"
+export ARM_PARTNER_ID="f85b2775-ec1d-4fef-949e-bbd6957082af"
+
+rover \
+ -lz /tf/caf/landingzones/caf_launchpad \
+ -var-folder /tf/caf/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level0/launchpad \
+ -launchpad \
+ -env ${caf_env} \
+ -level level0 \
+ -a plan
+```
+## Level 1
+
+### Shared Services
+
+```bash
+
+rover \
+ -lz /tf/caf/landingzones/caf_solution \
+ -var-folder /tf/caf/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level1/shared_services \
+ -tfstate shared_services.tfstate \
+ -env ${caf_env} \
+ -level level1 \
+ -a plan
+
+```
+### Networking Hub
+
+```bash
+
+rover \
+ -lz /tf/caf/landingzones/caf_solution \
+ -var-folder /tf/caf/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level1/networking_hub \
+ -tfstate networking_hub.tfstate \
+ -env ${caf_env} \
+ -level level1 \
+ -a plan
+
+```
+
+### Networking Spoke
+
+```bash
+
+rover \
+ -lz /tf/caf/landingzones/caf_solution \
+ -var-folder /tf/caf/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level1/networking_spoke \
+ -tfstate networking_spoke.tfstate \
+ -env ${caf_env} \
+ -level level1 \
+ -a plan
+
+```
+## Level 2
+
+### AKS
+
+```bash
+
+rover \
+ -lz /tf/caf/landingzones/caf_solution \
+ -var-folder /tf/caf/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level2/aks \
+ -tfstate aks.tfstate \
+ -env ${caf_env} \
+ -level level2 \
+ -a plan
+
+```
+
+### AKS Secure Baseline
+
+```bash
+
+rover \
+ -lz /tf/caf/landingzones/caf_solution/add-ons/aks_secure_baseline_v2 \
+ -var-folder /tf/caf/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level2/aks_secure_baseline \
+ -tfstate aks_secure_baseline.tfstate \
+ -env ${caf_env} \
+ -level level2 \
+ -a plan
+
+
+```
+
+## Deploying construction set with IaC
+In order to deploy the construction set with an IaC pipeline to automate the process follow the [Deploying construction set with IaC](./docs/iac-pipeline.md).
+
+## Next step
+
+:arrow_forward: [Deploy sample workload into AKS](./docs/aks.md)
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level0/launchpad/dynamic_secrets.tfvars b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level0/launchpad/dynamic_secrets.tfvars
new file mode 100644
index 00000000..23a0258d
--- /dev/null
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level0/launchpad/dynamic_secrets.tfvars
@@ -0,0 +1,114 @@
+
+# Store output attributes into keyvault secret
+# Those values are used by the rover to connect the current remote state and
+# identity the lower level
+dynamic_keyvault_secrets = {
+ level0 = {
+ subscription_id = {
+ output_key = "client_config"
+ attribute_key = "subscription_id"
+ secret_name = "subscription-id"
+ }
+ tenant_id = {
+ output_key = "client_config"
+ attribute_key = "tenant_id"
+ secret_name = "tenant-id"
+ }
+ }
+ level1 = {
+ lower_stg = {
+ output_key = "storage_accounts"
+ resource_key = "level0"
+ attribute_key = "name"
+ secret_name = "lower-storage-account-name"
+ }
+ lower_rg = {
+ output_key = "resource_groups"
+ resource_key = "level0"
+ attribute_key = "name"
+ secret_name = "lower-resource-group-name"
+ }
+ subscription_id = {
+ output_key = "client_config"
+ attribute_key = "subscription_id"
+ secret_name = "subscription-id"
+ }
+ tenant_id = {
+ output_key = "client_config"
+ attribute_key = "tenant_id"
+ secret_name = "tenant-id"
+ }
+ }
+ level2 = {
+ lower_stg = {
+ output_key = "storage_accounts"
+ resource_key = "level1"
+ attribute_key = "name"
+ secret_name = "lower-storage-account-name"
+ }
+ lower_rg = {
+ output_key = "resource_groups"
+ resource_key = "level1"
+ attribute_key = "name"
+ secret_name = "lower-resource-group-name"
+ }
+ subscription_id = {
+ output_key = "client_config"
+ attribute_key = "subscription_id"
+ secret_name = "subscription-id"
+ }
+ tenant_id = {
+ output_key = "client_config"
+ attribute_key = "tenant_id"
+ secret_name = "tenant-id"
+ }
+ }
+ level3 = {
+ lower_stg = {
+ output_key = "storage_accounts"
+ resource_key = "level2"
+ attribute_key = "name"
+ secret_name = "lower-storage-account-name"
+ }
+ lower_rg = {
+ output_key = "resource_groups"
+ resource_key = "level2"
+ attribute_key = "name"
+ secret_name = "lower-resource-group-name"
+ }
+ subscription_id = {
+ output_key = "client_config"
+ attribute_key = "subscription_id"
+ secret_name = "subscription-id"
+ }
+ tenant_id = {
+ output_key = "client_config"
+ attribute_key = "tenant_id"
+ secret_name = "tenant-id"
+ }
+ }
+ level4 = {
+ lower_stg = {
+ output_key = "storage_accounts"
+ resource_key = "level3"
+ attribute_key = "name"
+ secret_name = "lower-storage-account-name"
+ }
+ lower_rg = {
+ output_key = "resource_groups"
+ resource_key = "level3"
+ attribute_key = "name"
+ secret_name = "lower-resource-group-name"
+ }
+ subscription_id = {
+ output_key = "client_config"
+ attribute_key = "subscription_id"
+ secret_name = "subscription-id"
+ }
+ tenant_id = {
+ output_key = "client_config"
+ attribute_key = "tenant_id"
+ secret_name = "tenant-id"
+ }
+ }
+}
\ No newline at end of file
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level0/launchpad/global_settings.tfvars b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level0/launchpad/global_settings.tfvars
new file mode 100644
index 00000000..34ca53dd
--- /dev/null
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level0/launchpad/global_settings.tfvars
@@ -0,0 +1,32 @@
+
+# Do not change the following values
+passthrough = false
+# random_length = 3
+inherit_tags = true
+# prefix = "esaks"
+
+# Default region. When not set to a resource it will use that value
+default_region = "region1"
+
+regions = {
+ region1 = "southeastasia"
+ region2 = "eastasia"
+}
+
+launchpad_key_names = {
+ keyvault = "level0"
+ tfstates = [
+ "level0",
+ "level1",
+ "level2",
+ "level3",
+ "level4"
+ ]
+}
+
+tags = {
+ Project_Code = "CAF-TF"
+ Name = "CAF Terraform Landingzones and solutions"
+ Data_Classification = "Internal"
+ Application_Classification = "Standard"
+}
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level0/launchpad/keyvaults.tfvars b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level0/launchpad/keyvaults.tfvars
new file mode 100644
index 00000000..a05179e3
--- /dev/null
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level0/launchpad/keyvaults.tfvars
@@ -0,0 +1,94 @@
+
+keyvaults = {
+ level0 = {
+ name = "level0"
+ resource_group_key = "level0"
+ sku_name = "standard"
+ soft_delete_enabled = true
+ tags = {
+ tfstate = "level0"
+ }
+
+ creation_policies = {
+ logged_in_user = {
+ # if the key is set to "logged_in_user" add the user running terraform in the keyvault policy
+ # More examples in /examples/keyvault
+ secret_permissions = ["Set", "Get", "List", "Delete", "Purge", "Recover"]
+ }
+ }
+
+ }
+
+ level1 = {
+ name = "level1"
+ resource_group_key = "level1"
+ sku_name = "standard"
+ soft_delete_enabled = true
+ tags = {
+ tfstate = "level1"
+ }
+
+ creation_policies = {
+ logged_in_user = {
+ # if the key is set to "logged_in_user" add the user running terraform in the keyvault policy
+ # More examples in /examples/keyvault
+ secret_permissions = ["Set", "Get", "List", "Delete", "Purge", "Recover"]
+ }
+ }
+ }
+
+ level2 = {
+ name = "level2"
+ resource_group_key = "level2"
+ sku_name = "standard"
+ soft_delete_enabled = true
+ tags = {
+ tfstate = "level2"
+ }
+
+ creation_policies = {
+ logged_in_user = {
+ # if the key is set to "logged_in_user" add the user running terraform in the keyvault policy
+ # More examples in /examples/keyvault
+ secret_permissions = ["Set", "Get", "List", "Delete", "Purge", "Recover"]
+ }
+ }
+
+ }
+
+ level3 = {
+ name = "level3"
+ resource_group_key = "level3"
+ sku_name = "standard"
+ soft_delete_enabled = true
+ tags = {
+ tfstate = "level3"
+ }
+
+ creation_policies = {
+ logged_in_user = {
+ # if the key is set to "logged_in_user" add the user running terraform in the keyvault policy
+ # More examples in /examples/keyvault
+ secret_permissions = ["Set", "Get", "List", "Delete", "Purge", "Recover"]
+ }
+ }
+ }
+
+ level4 = {
+ name = "level4"
+ resource_group_key = "level4"
+ sku_name = "standard"
+ soft_delete_enabled = true
+ tags = {
+ tfstate = "level4"
+ }
+
+ creation_policies = {
+ logged_in_user = {
+ # if the key is set to "logged_in_user" add the user running terraform in the keyvault policy
+ # More examples in /examples/keyvault
+ secret_permissions = ["Set", "Get", "List", "Delete", "Purge", "Recover"]
+ }
+ }
+ }
+}
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level0/launchpad/landingzone.tfvars b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level0/launchpad/landingzone.tfvars
new file mode 100644
index 00000000..83de35a9
--- /dev/null
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level0/launchpad/landingzone.tfvars
@@ -0,0 +1,5 @@
+landingzone = {
+ backend_type = "azurerm"
+ level = "level0"
+ key = "launchpad"
+}
\ No newline at end of file
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level0/launchpad/resource_groups.tfvars b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level0/launchpad/resource_groups.tfvars
new file mode 100644
index 00000000..4511544a
--- /dev/null
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level0/launchpad/resource_groups.tfvars
@@ -0,0 +1,36 @@
+
+resource_groups = {
+ level0 = {
+ name = "caf-launchpad-level0"
+ tags = {
+ level = "level0"
+ }
+ }
+ level1 = {
+ name = "caf-launchpad-level1"
+ tags = {
+ level = "level1"
+ }
+ }
+ level2 = {
+ name = "caf-launchpad-level2"
+ tags = {
+ level = "level2"
+ }
+ }
+ level3 = {
+ name = "caf-launchpad-level3"
+ tags = {
+ level = "level3"
+ }
+ }
+ level4 = {
+ name = "caf-launchpad-level4"
+ tags = {
+ level = "level4"
+ }
+ }
+ security = {
+ name = "caf-launchpad-security"
+ }
+}
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level0/launchpad/storage_accounts.tfvars b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level0/launchpad/storage_accounts.tfvars
new file mode 100644
index 00000000..9e0359e6
--- /dev/null
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level0/launchpad/storage_accounts.tfvars
@@ -0,0 +1,106 @@
+
+storage_accounts = {
+ level0 = {
+ name = "cafl0"
+ resource_group_key = "level0"
+ account_kind = "BlobStorage"
+ account_tier = "Standard"
+ account_replication_type = "LRS"
+ tags = {
+ ## Those tags must never be changed after being set as they are used by the rover to locate the launchpad and the tfstates.
+ # Only adjust the environment value at creation time
+ tfstate = "level0"
+ environment = "prod"
+ launchpad = "launchpad"
+ ##
+ }
+ containers = {
+ tfstate = {
+ name = "tfstate"
+ }
+ }
+ }
+
+ level1 = {
+ name = "cafl1"
+ resource_group_key = "level1"
+ account_kind = "BlobStorage"
+ account_tier = "Standard"
+ account_replication_type = "LRS"
+ tags = {
+ # Those tags must never be changed while set as they are used by the rover to locate the launchpad and the tfstates.
+ tfstate = "level1"
+ environment = "prod"
+ launchpad = "launchpad"
+ }
+ containers = {
+ tfstate = {
+ name = "tfstate"
+ }
+ }
+ }
+
+ level2 = {
+ name = "cafl2"
+ resource_group_key = "level2"
+ account_kind = "BlobStorage"
+ account_tier = "Standard"
+ account_replication_type = "LRS"
+ tags = {
+ # Those tags must never be changed while set as they are used by the rover to locate the launchpad and the tfstates.
+ tfstate = "level2"
+ environment = "prod"
+ launchpad = "launchpad"
+ }
+ containers = {
+ tfstate = {
+ name = "tfstate"
+ }
+ }
+ }
+
+ level3 = {
+ name = "cafl3"
+ resource_group_key = "level3"
+ account_kind = "BlobStorage"
+ account_tier = "Standard"
+ account_replication_type = "LRS"
+ tags = {
+ # Those tags must never be changed while set as they are used by the rover to locate the launchpad and the tfstates.
+ tfstate = "level3"
+ environment = "prod"
+ launchpad = "launchpad"
+ }
+ containers = {
+ tfstate = {
+ name = "tfstate"
+ }
+ }
+ }
+
+ level4 = {
+ name = "cafl4"
+ resource_group_key = "level4"
+ account_kind = "BlobStorage"
+ account_tier = "Standard"
+ account_replication_type = "LRS"
+ tags = {
+ # Those tags must never be changed while set as they are used by the rover to locate the launchpad and the tfstates.
+ tfstate = "level4"
+ environment = "prod"
+ launchpad = "launchpad"
+ }
+ containers = {
+ tfstate = {
+ name = "tfstate"
+ }
+ assnp = {
+ name = "assnp"
+ }
+ assp = {
+ name = "assp"
+ }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/configuration/networking/firewall_application_rule_collection_definition.tfvars b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level1/networking_hub/firewall_application_rule_collection_definition.tfvars
similarity index 96%
rename from enterprise_scale/construction_sets/aks/online/aks_secure_baseline/configuration/networking/firewall_application_rule_collection_definition.tfvars
rename to enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level1/networking_hub/firewall_application_rule_collection_definition.tfvars
index 6fb9afc4..91662f18 100644
--- a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/configuration/networking/firewall_application_rule_collection_definition.tfvars
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level1/networking_hub/firewall_application_rule_collection_definition.tfvars
@@ -100,8 +100,11 @@ azurerm_firewall_application_rule_collection_definition = {
]
target_fqdns = [
"api.github.com",
+ "ghcr.io",
+ "*.ghcr.io",
"github.com",
- "github-production-release-asset-2e65be.s3.amazonaws.com",
+ "*.githubusercontent.com",
+ "charts.bitnami.com"
]
protocol = {
http = {
@@ -132,4 +135,4 @@ azurerm_firewall_application_rule_collection_definition = {
},
}
}
-}
\ No newline at end of file
+}
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/configuration/networking/firewall_network_rule_collection_definition.tfvars b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level1/networking_hub/firewall_network_rule_collection_definition.tfvars
similarity index 100%
rename from enterprise_scale/construction_sets/aks/online/aks_secure_baseline/configuration/networking/firewall_network_rule_collection_definition.tfvars
rename to enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level1/networking_hub/firewall_network_rule_collection_definition.tfvars
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/configuration/networking/firewalls.tfvars b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level1/networking_hub/firewalls.tfvars
similarity index 100%
rename from enterprise_scale/construction_sets/aks/online/aks_secure_baseline/configuration/networking/firewalls.tfvars
rename to enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level1/networking_hub/firewalls.tfvars
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level1/networking_hub/ip_groups.tfvars b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level1/networking_hub/ip_groups.tfvars
new file mode 100644
index 00000000..d7a04cdd
--- /dev/null
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level1/networking_hub/ip_groups.tfvars
@@ -0,0 +1,9 @@
+ip_groups = {
+ aks_ip_group1 = {
+ name = "aks_ip_group1"
+ cidrs = ["10.100.80.0/22"] # if cidrs is defined all vnet & subnet are ignored
+ resource_group_key = "vnet_hub_re1"
+ # vnet_key = "vnet_aks_re1"
+ # subnet_keys = ["aks_nodepool_system","aks_nodepool_user1"] # can be either unclared or empty, will take vnet cidr instead
+ }
+}
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level1/networking_hub/landingzone.tfvars b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level1/networking_hub/landingzone.tfvars
new file mode 100644
index 00000000..59e8a965
--- /dev/null
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level1/networking_hub/landingzone.tfvars
@@ -0,0 +1,16 @@
+landingzone = {
+ backend_type = "azurerm"
+ global_settings_key = "launchpad"
+ level = "level1"
+ key = "networking_hub"
+ tfstates = {
+ launchpad = {
+ level = "lower"
+ tfstate = "caf_launchpad.tfstate"
+ }
+ shared_services = {
+ level = "current"
+ tfstate = "shared_services.tfstate"
+ }
+ }
+}
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level1/networking_hub/networking.tfvars b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level1/networking_hub/networking.tfvars
new file mode 100644
index 00000000..8cb11630
--- /dev/null
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level1/networking_hub/networking.tfvars
@@ -0,0 +1,37 @@
+vnets = {
+ vnet_hub_re1 = {
+ resource_group_key = "vnet_hub_re1"
+ region = "region1"
+ vnet = {
+ name = "vnet_hub_re1"
+ address_space = ["100.64.100.0/22"]
+ }
+ specialsubnets = {
+ GatewaySubnet = {
+ name = "GatewaySubnet" #Must be called GateWaySubnet in order to host a Virtual Network Gateway
+ cidr = ["100.64.100.0/27"]
+ }
+ AzureFirewallSubnet = {
+ name = "AzureFirewallSubnet" #Must be called AzureFirewallSubnet
+ cidr = ["100.64.101.0/26"]
+ }
+ }
+ subnets = {
+ AzureBastionSubnet = {
+ name = "AzureBastionSubnet" #Must be called AzureBastionSubnet
+ cidr = ["100.64.101.64/26"]
+ nsg_key = "azure_bastion_nsg"
+ }
+ jumpbox = {
+ name = "jumpbox"
+ cidr = ["100.64.102.0/27"]
+ nsg_key = "jumpbox"
+ }
+ private_endpoints = {
+ name = "private_endpoints"
+ cidr = ["100.64.103.128/25"]
+ enforce_private_link_endpoint_network_policies = true
+ }
+ }
+ }
+} //vnets
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level1/networking_hub/nsg.tfvars b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level1/networking_hub/nsg.tfvars
new file mode 100644
index 00000000..881ea7a5
--- /dev/null
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level1/networking_hub/nsg.tfvars
@@ -0,0 +1,149 @@
+
+#
+# Definition of the networking security groups
+#
+network_security_group_definition = {
+ # This entry is applied to all subnets with no NSG defined
+ azure_bastion_nsg = {
+ nsg = [
+ {
+ name = "in-allow-https",
+ priority = "120"
+ direction = "Inbound"
+ access = "Allow"
+ protocol = "tcp"
+ source_port_range = "*"
+ destination_port_range = "443"
+ source_address_prefix = "Internet"
+ destination_address_prefix = "*"
+ },
+ {
+ name = "in-allow-gateway-manager",
+ priority = "130"
+ direction = "Inbound"
+ access = "Allow"
+ protocol = "tcp"
+ source_port_range = "*"
+ destination_port_range = "443"
+ source_address_prefix = "GatewayManager"
+ destination_address_prefix = "*"
+ },
+ {
+ name = "in-allow-load-balancer",
+ priority = "140"
+ direction = "Inbound"
+ access = "Allow"
+ protocol = "tcp"
+ source_port_range = "*"
+ destination_port_range = "443"
+ source_address_prefix = "AzureLoadBalancer"
+ destination_address_prefix = "*"
+ },
+ {
+ name = "in-allow-bastion-host-communication-8080",
+ priority = "150"
+ direction = "Inbound"
+ access = "Allow"
+ protocol = "*"
+ source_port_range = "*"
+ destination_port_range = "8080"
+ source_address_prefix = "VirtualNetwork"
+ destination_address_prefix = "VirtualNetwork"
+ },
+ {
+ name = "in-allow-bastion-host-communication-5701",
+ priority = "151"
+ direction = "Inbound"
+ access = "Allow"
+ protocol = "*"
+ source_port_range = "*"
+ destination_port_range = "5701"
+ source_address_prefix = "VirtualNetwork"
+ destination_address_prefix = "VirtualNetwork"
+ },
+ {
+ name = "out-vnet-allow-22",
+ priority = "100"
+ direction = "Outbound"
+ access = "Allow"
+ protocol = "*"
+ source_port_range = "*"
+ destination_port_range = "22"
+ source_address_prefix = "*"
+ destination_address_prefix = "VirtualNetwork"
+ },
+ {
+ name = "out-vnet-allow-3389",
+ priority = "101"
+ direction = "Outbound"
+ access = "Allow"
+ protocol = "*"
+ source_port_range = "*"
+ destination_port_range = "3389"
+ source_address_prefix = "*"
+ destination_address_prefix = "VirtualNetwork"
+ },
+ {
+ name = "out-azure-cloud-allow-3389",
+ priority = "110"
+ direction = "Outbound"
+ access = "Allow"
+ protocol = "tcp"
+ source_port_range = "*"
+ destination_port_range = "443"
+ source_address_prefix = "*"
+ destination_address_prefix = "AzureCloud"
+ },
+ {
+ name = "out-communication-allow-8080",
+ priority = "120"
+ direction = "Outbound"
+ access = "Allow"
+ protocol = "tcp"
+ source_port_range = "*"
+ destination_port_range = "8080"
+ source_address_prefix = "VirtualNetwork"
+ destination_address_prefix = "VirtualNetwork"
+ },
+ {
+ name = "out-communication-allow-5701",
+ priority = "121"
+ direction = "Outbound"
+ access = "Allow"
+ protocol = "tcp"
+ source_port_range = "*"
+ destination_port_range = "5701"
+ source_address_prefix = "VirtualNetwork"
+ destination_address_prefix = "VirtualNetwork"
+ },
+ {
+ name = "out-gateway-information-allow",
+ priority = "130"
+ direction = "Outbound"
+ access = "Allow"
+ protocol = "*"
+ source_port_range = "*"
+ destination_port_range = "80"
+ source_address_prefix = "*"
+ destination_address_prefix = "Internet"
+ }
+ ]
+ }
+
+ jumpbox = {
+ nsg = [
+ {
+ name = "ssh-inbound-22",
+ priority = "200"
+ direction = "Inbound"
+ access = "Allow"
+ protocol = "tcp"
+ source_port_range = "*"
+ destination_port_range = "22"
+ source_address_prefix = "*"
+ destination_address_prefix = "VirtualNetwork"
+ },
+ ]
+ }
+
+}
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level1/networking_hub/public_ips.tfvars b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level1/networking_hub/public_ips.tfvars
new file mode 100644
index 00000000..d36d11e4
--- /dev/null
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level1/networking_hub/public_ips.tfvars
@@ -0,0 +1,31 @@
+public_ip_addresses = {
+ firewall_re1 = {
+ name = "egress-pip1"
+ resource_group_key = "vnet_hub_re1"
+ sku = "Standard"
+ allocation_method = "Static"
+ ip_version = "IPv4"
+ idle_timeout_in_minutes = "4"
+
+ }
+
+ firewall_pip2_re1 = {
+ name = "egress-pip2"
+ resource_group_key = "vnet_hub_re1"
+ sku = "Standard"
+ allocation_method = "Static"
+ ip_version = "IPv4"
+ idle_timeout_in_minutes = "4"
+
+ }
+
+ bastion_host_re1 = {
+ name = "bastion-pip1"
+ resource_group_key = "jumpbox_re1"
+ sku = "Standard"
+ allocation_method = "Static"
+ ip_version = "IPv4"
+ idle_timeout_in_minutes = "4"
+ }
+
+}
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level1/networking_hub/resource_groups.tfvars b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level1/networking_hub/resource_groups.tfvars
new file mode 100644
index 00000000..0340efa9
--- /dev/null
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level1/networking_hub/resource_groups.tfvars
@@ -0,0 +1,11 @@
+resource_groups = {
+ vnet_hub_re1 = {
+ name = "vnet-hub-re1"
+ region = "region1"
+ }
+
+ jumpbox_re1 = {
+ name = "jumpbox_re1"
+ region = "region1"
+ }
+}
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level1/networking_spoke/landingzone.tfvars b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level1/networking_spoke/landingzone.tfvars
new file mode 100644
index 00000000..31b6c018
--- /dev/null
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level1/networking_spoke/landingzone.tfvars
@@ -0,0 +1,16 @@
+landingzone = {
+ backend_type = "azurerm"
+ global_settings_key = "launchpad"
+ level = "level1"
+ key = "networking_spoke"
+ tfstates = {
+ launchpad = {
+ level = "lower"
+ tfstate = "caf_launchpad.tfstate"
+ }
+ networking_hub = {
+ level = "current"
+ tfstate = "networking_hub.tfstate"
+ }
+ }
+}
\ No newline at end of file
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level1/networking_spoke/networking.tfvars b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level1/networking_spoke/networking.tfvars
new file mode 100644
index 00000000..b920b996
--- /dev/null
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level1/networking_spoke/networking.tfvars
@@ -0,0 +1,63 @@
+vnets = {
+ vnet_aks_re1 = {
+ resource_group_key = "aks_spoke_re1"
+ region = "region1"
+ vnet = {
+ name = "aks"
+ address_space = ["10.100.80.0/22"]
+ }
+ subnets = {
+ aks_nodepool_system = {
+ name = "aks_nodepool_system"
+ cidr = ["10.100.80.0/24"]
+ nsg_key = "azure_kubernetes_cluster_nsg"
+ route_table_key = "default_to_firewall_re1"
+ }
+ aks_nodepool_user1 = {
+ name = "aks_nodepool_user1"
+ cidr = ["10.100.81.0/24"]
+ nsg_key = "azure_kubernetes_cluster_nsg"
+ route_table_key = "default_to_firewall_re1"
+ }
+ aks_ingress = {
+ name = "aks_ingress"
+ cidr = ["10.100.82.0/24"]
+ nsg_key = "azure_kubernetes_cluster_nsg"
+ route_table_key = "default_to_firewall_re1"
+ }
+ jumpbox = {
+ name = "jumpbox"
+ cidr = ["10.100.83.64/28"]
+ nsg_key = "azure_kubernetes_cluster_nsg"
+ route_table_key = "default_to_firewall_re1"
+ }
+ private_endpoints = {
+ name = "private_endpoints"
+ cidr = ["10.100.83.0/27"]
+ enforce_private_link_endpoint_network_policies = true
+ }
+ AzureBastionSubnet = {
+ name = "AzureBastionSubnet" #Must be called AzureBastionSubnet
+ cidr = ["10.100.83.32/27"]
+ nsg_key = "azure_bastion_nsg"
+ }
+ application_gateway = {
+ name = "agw"
+ cidr = ["10.100.83.96/27"]
+ nsg_key = "application_gateway"
+ }
+ } //subnets
+
+
+ specialsubnets = {
+ AzureFirewallSubnet = {
+ name = "AzureFirewallSubnet" #Must be called AzureFirewallSubnet
+ cidr = ["10.100.83.128/26"]
+ }
+ GatewaySubnet = {
+ name = "GatewaySubnet" #Must be called GateWaySubnet in order to host a Virtual Network Gateway
+ cidr = ["10.100.83.224/27"]
+ }
+ } //specialsubnets
+ }
+} //vnets
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/configuration/networking/nsg.tfvars b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level1/networking_spoke/nsg.tfvars
similarity index 100%
rename from enterprise_scale/construction_sets/aks/online/aks_secure_baseline/configuration/networking/nsg.tfvars
rename to enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level1/networking_spoke/nsg.tfvars
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level1/networking_spoke/peerings.tfvars b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level1/networking_spoke/peerings.tfvars
new file mode 100644
index 00000000..463a96aa
--- /dev/null
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level1/networking_spoke/peerings.tfvars
@@ -0,0 +1,34 @@
+vnet_peerings = {
+ vnet_aks_re1_TO_vnet_hub_re1 = {
+ name = "vnet_aks_re1_TO_vnet_hub_re1"
+ from = {
+ vnet_key = "vnet_aks_re1"
+ }
+ to = {
+ lz_key = "networking_hub"
+ output_key = "vnets"
+ vnet_key = "vnet_hub_re1"
+ }
+ allow_virtual_network_access = true
+ allow_forwarded_traffic = false
+ allow_gateway_transit = false
+ use_remote_gateways = false
+ }
+
+ vnet_hub_re1_TO_vnet_aks_re1 = {
+ name = "vnet_hub_re1_TO_vnet_aks_re1"
+ from = {
+ lz_key = "networking_hub"
+ output_key = "vnets"
+ vnet_key = "vnet_hub_re1"
+ }
+ to = {
+ vnet_key = "vnet_aks_re1"
+ }
+ allow_virtual_network_access = true
+ allow_forwarded_traffic = true
+ allow_gateway_transit = true
+ use_remote_gateways = false
+ }
+
+}
\ No newline at end of file
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/configuration/networking/private_dns.tfvars b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level1/networking_spoke/private_dns.tfvars
similarity index 100%
rename from enterprise_scale/construction_sets/aks/online/aks_secure_baseline/configuration/networking/private_dns.tfvars
rename to enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level1/networking_spoke/private_dns.tfvars
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level1/networking_spoke/resource_groups.tfvars b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level1/networking_spoke/resource_groups.tfvars
new file mode 100644
index 00000000..2ba5b2c4
--- /dev/null
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level1/networking_spoke/resource_groups.tfvars
@@ -0,0 +1,6 @@
+resource_groups = {
+ aks_spoke_re1 = {
+ name = "aks_spoke_re1"
+ region = "region1"
+ }
+}
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level1/networking_spoke/route_tables.tfvars b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level1/networking_spoke/route_tables.tfvars
new file mode 100644
index 00000000..e4ccb160
--- /dev/null
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level1/networking_spoke/route_tables.tfvars
@@ -0,0 +1,27 @@
+route_tables = {
+ default_to_firewall_re1 = {
+ name = "default_to_firewall_re1"
+ resource_group_key = "aks_spoke_re1"
+ }
+}
+
+azurerm_routes = {
+
+ default_to_firewall_re1 = {
+ name = "0-0-0-0-through-firewall-re1"
+ resource_group_key = "aks_spoke_re1"
+ route_table_key = "default_to_firewall_re1"
+ address_prefix = "0.0.0.0/0"
+ next_hop_type = "VirtualAppliance"
+ next_hop_type_key = "azurerm_firewall"
+
+ # To be set when next_hop_type = "VirtualAppliance"
+ private_ip_keys = {
+ azurerm_firewall = {
+ lz_key = "networking_hub"
+ key = "fw_re1"
+ interface_index = 0
+ }
+ }
+ }
+}
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/configuration/monitor/diagnostics.tfvars b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level1/shared_services/diagnostics.tfvars
similarity index 100%
rename from enterprise_scale/construction_sets/aks/online/aks_secure_baseline/configuration/monitor/diagnostics.tfvars
rename to enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level1/shared_services/diagnostics.tfvars
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level1/shared_services/landingzone.tfvars b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level1/shared_services/landingzone.tfvars
new file mode 100644
index 00000000..834c4a64
--- /dev/null
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level1/shared_services/landingzone.tfvars
@@ -0,0 +1,12 @@
+landingzone = {
+ backend_type = "azurerm"
+ global_settings_key = "launchpad"
+ level = "level1"
+ key = "shared_services"
+ tfstates = {
+ launchpad = {
+ level = "lower"
+ tfstate = "caf_launchpad.tfstate"
+ }
+ }
+}
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/configuration/monitor/log_analytics.tfvars b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level1/shared_services/log_analytics.tfvars
similarity index 100%
rename from enterprise_scale/construction_sets/aks/online/aks_secure_baseline/configuration/monitor/log_analytics.tfvars
rename to enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level1/shared_services/log_analytics.tfvars
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level1/shared_services/resource_groups.tfvars b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level1/shared_services/resource_groups.tfvars
new file mode 100644
index 00000000..6c0a8e83
--- /dev/null
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level1/shared_services/resource_groups.tfvars
@@ -0,0 +1,6 @@
+resource_groups = {
+ ops_re1 = {
+ name = "ops_re1"
+ region = "region1"
+ }
+}
\ No newline at end of file
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level2/aks/agw.tfvars b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level2/aks/agw.tfvars
new file mode 100644
index 00000000..1325e78b
--- /dev/null
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level2/aks/agw.tfvars
@@ -0,0 +1,64 @@
+application_gateways = {
+ agw1_az1 = {
+ resource_group_key = "agw_re1"
+ name = "app_gateway"
+ vnet_key = "vnet_aks_re1"
+ subnet_key = "application_gateway"
+ lz_key = "networking_spoke"
+ sku_name = "WAF_v2"
+ sku_tier = "WAF_v2"
+ capacity = {
+ autoscale = {
+ minimum_scale_unit = 0
+ maximum_scale_unit = 10
+ }
+ }
+ zones = ["1"]
+ enable_http2 = true
+
+ identity = {
+ managed_identity_keys = [
+ "apgw_keyvault_secrets"
+ ]
+ }
+
+ front_end_ip_configurations = {
+ public = {
+ name = "public"
+ lz_key = "networking_spoke"
+ public_ip_key = "agw_pip1_re1"
+ subnet_key = "application_gateway"
+ }
+ private = {
+ name = "private"
+ lz_key = "networking_spoke"
+ 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"
+ }
+ }
+
+ front_end_ports = {
+ 80 = {
+ name = "http-80"
+ port = 80
+ protocol = "Http"
+ }
+ 443 = {
+ name = "https-443"
+ port = 443
+ protocol = "Https"
+ }
+ }
+
+ trusted_root_certificate = {
+ wildcard_ingress = {
+ name = "wildcard-ingress"
+ # data =
+ keyvault_key = "secrets"
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/configuration/agw/agw_application.tfvars b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level2/aks/agw_application.tfvars
similarity index 100%
rename from enterprise_scale/construction_sets/aks/online/aks_secure_baseline/configuration/agw/agw_application.tfvars
rename to enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level2/aks/agw_application.tfvars
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level2/aks/aks.tfvars b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level2/aks/aks.tfvars
new file mode 100644
index 00000000..ed046e04
--- /dev/null
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level2/aks/aks.tfvars
@@ -0,0 +1,101 @@
+aks_clusters = {
+ cluster_re1 = {
+ name = "akscluster-re1-001"
+ resource_group_key = "aks_re1"
+ os_type = "Linux"
+
+ diagnostic_profiles = {
+ operations = {
+ name = "aksoperations"
+ definition_key = "azure_kubernetes_cluster"
+ destination_type = "log_analytics"
+ destination_key = "central_logs"
+ }
+ }
+
+ identity = {
+ type = "SystemAssigned"
+ }
+
+
+ # kubernetes_version = "1.20.5"
+ lz_key = "networking_spoke"
+ vnet_key = "vnet_aks_re1"
+
+ # network plugin and network policy should be "azure" (recommended by Secure AKS baseline)
+ network_profile = {
+ network_plugin = "azure"
+ load_balancer_sku = "Standard"
+ outbound_type = "userDefinedRouting"
+ }
+
+ # until the issue with Flux and Azure policy is resolved https://github.com/fluxcd/flux2/issues/703
+ #network_policy = "azure"
+
+ role_based_access_control = {
+ enabled = true
+ azure_active_directory = {
+ managed = true
+ # admin_group_object_ids = ["7304e4e7-b148-4ada-a135-6049c702d21e"]
+ admin_groups = {
+ keys = ["aks_cluster_re1_admins"]
+ }
+ }
+ }
+
+
+ addon_profile = {
+ oms_agent = {
+ enabled = true
+ log_analytics_key = "central_logs_region1"
+ }
+ azure_policy = {
+ enabled = true
+ }
+ }
+
+
+ load_balancer_profile = {
+ # Only one option can be set
+ managed_outbound_ip_count = 1
+ # outbound_ip_prefix_ids = []
+ # outbound_ip_address_ids = []
+ }
+
+ default_node_pool = {
+ name = "sharedsvc"
+ vm_size = "Standard_DS2_v2"
+ subnet_key = "aks_nodepool_system"
+ enabled_auto_scaling = false
+ enable_node_public_ip = false
+ max_pods = 30
+ node_count = 3
+ os_disk_type = "Ephemeral"
+ os_disk_size_gb = 80
+ # orchestrator_version = "1.20.5"
+ tags = {
+ "project" = "system services"
+ }
+ }
+
+ node_resource_group_name = "aks-nodes-re1"
+
+ node_pools = {
+ pool1 = {
+ name = "npuser01"
+ mode = "User"
+ subnet_key = "aks_nodepool_user1"
+ max_pods = 30
+ vm_size = "Standard_DS3_v2"
+ node_count = 3
+ os_disk_type = "Ephemeral"
+ enable_auto_scaling = false
+ os_disk_size_gb = 120
+ # orchestrator_version = "1.20.5"
+ tags = {
+ "project" = "user services"
+ }
+ }
+ }
+ }
+}
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/configuration/keyvault/certificate_requests.tfvars b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level2/aks/certificate_requests.tfvars
similarity index 100%
rename from enterprise_scale/construction_sets/aks/online/aks_secure_baseline/configuration/keyvault/certificate_requests.tfvars
rename to enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level2/aks/certificate_requests.tfvars
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level2/aks/domain.tfvars b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level2/aks/domain.tfvars
new file mode 100644
index 00000000..109a9ea4
--- /dev/null
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level2/aks/domain.tfvars
@@ -0,0 +1,72 @@
+dns_zones = {
+ dns_zone1 = {
+ name = "" // Set as empty for CI. this will creation a random_domain_name.com
+ resource_group_key = "agw_re1"
+
+ # You can create dns records using the following nested structure
+ records = {
+ a = {
+ agw = {
+ name = "@"
+ # records = ["10.0.0.0"]
+ resource_id = {
+ public_ip_address = {
+ key = "agw_pip1_re1"
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+domain_name_registrations = {
+ #
+ # Register for a random domain name
+ # As dnsType as not be set
+ #
+ random_domain = {
+ name = "" // Set as empty for CI. this will creation a random_domain_name.com
+ resource_group_key = "agw_re1"
+
+ auto_renew = true
+ privacy = true
+ lock_resource = false
+ dns_zone = {
+ # Set the resource ID of the existing DNS zone
+ # id = "/subscriptions/[subscription_id]/resourceGroups/qaxu-rg-dns-domain-registrar/providers/Microsoft.Network/dnszones/ml0iaix4xgnz0jqd.com"
+ #
+ # or
+ #
+ # Set the 'key' of the dns_zone created in this deployment
+ # Set 'lz_key' if the DNS zone referenced by the key attribute has been created in a remote deployment
+ key = "dns_zone1"
+ }
+
+ contacts = {
+ contactAdmin = {
+ name_first = "John"
+ name_last = "Doe"
+ email = "test@contoso.com"
+ phone = "+65.12345678"
+ organization = "Sandpit"
+ job_title = "Engineer"
+ address1 = "Singapore"
+ address2 = ""
+ postal_code = "018898"
+ state = "Singapore"
+ city = "Singapore"
+ country = "SG"
+ }
+ contactBilling = {
+ same_as_admin = true
+ }
+ contactRegistrant = {
+ same_as_admin = true
+ }
+ contactTechnical = {
+ same_as_admin = true
+ }
+ }
+ }
+}
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level2/aks/iam_aad.ignore b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level2/aks/iam_aad.ignore
new file mode 100644
index 00000000..a9cc6668
--- /dev/null
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level2/aks/iam_aad.ignore
@@ -0,0 +1,18 @@
+# Create Azure Active Directory Groups
+azuread_groups = {
+
+ # cluster_re1 AKS admin group
+ #
+ aks_cluster_re1_admins = {
+ name = "aks-cluster-re1-admins"
+ description = "Provide read and write access to the keyvault secrets / level0."
+ members = {
+ user_principal_names = [
+ # You can add the UPN to be part of this AKS admin group
+ ]
+ # You can add the object IDs of existing Azure Ad groups or users
+ object_ids = []
+ }
+ prevent_duplicate_name = false
+ }
+}
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/configuration/iam/iam_managed_identities.tfvars b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level2/aks/iam_managed_identities.tfvars
similarity index 100%
rename from enterprise_scale/construction_sets/aks/online/aks_secure_baseline/configuration/iam/iam_managed_identities.tfvars
rename to enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level2/aks/iam_managed_identities.tfvars
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/configuration/iam/iam_role_mappings.tfvars b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level2/aks/iam_role_mappings.tfvars
similarity index 100%
rename from enterprise_scale/construction_sets/aks/online/aks_secure_baseline/configuration/iam/iam_role_mappings.tfvars
rename to enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level2/aks/iam_role_mappings.tfvars
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/configuration/keyvault/keyvaults.tfvars b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level2/aks/keyvaults.tfvars
similarity index 100%
rename from enterprise_scale/construction_sets/aks/online/aks_secure_baseline/configuration/keyvault/keyvaults.tfvars
rename to enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level2/aks/keyvaults.tfvars
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level2/aks/landingzone.tfvars b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level2/aks/landingzone.tfvars
new file mode 100644
index 00000000..2794ea79
--- /dev/null
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level2/aks/landingzone.tfvars
@@ -0,0 +1,16 @@
+landingzone = {
+ backend_type = "azurerm"
+ global_settings_key = "shared_services"
+ level = "level2"
+ key = "aks"
+ tfstates = {
+ shared_services = {
+ level = "lower"
+ tfstate = "shared_services.tfstate"
+ }
+ networking_spoke = {
+ level = "lower"
+ tfstate = "networking_spoke.tfstate"
+ }
+ }
+}
\ No newline at end of file
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level2/aks/public_ips.tfvars b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level2/aks/public_ips.tfvars
new file mode 100644
index 00000000..68d6bf07
--- /dev/null
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level2/aks/public_ips.tfvars
@@ -0,0 +1,11 @@
+public_ip_addresses = {
+ agw_pip1_re1 = {
+ name = "agw_pip1"
+ resource_group_key = "agw_re1"
+ sku = "Standard"
+ allocation_method = "Static"
+ ip_version = "IPv4"
+ zones = ["1"]
+ idle_timeout_in_minutes = "4"
+ }
+}
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level2/aks/resource_groups.tfvars b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level2/aks/resource_groups.tfvars
new file mode 100644
index 00000000..187e1fd4
--- /dev/null
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level2/aks/resource_groups.tfvars
@@ -0,0 +1,14 @@
+resource_groups = {
+ aks_re1 = {
+ name = "aks-re1"
+ region = "region1"
+ }
+ agw_re1 = {
+ name = "agw-re1"
+ region = "region1"
+ }
+ devops_re1 = {
+ name = "devops_re1"
+ region = "region1"
+ }
+}
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level2/aks_secure_baseline/aks.tfvars b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level2/aks_secure_baseline/aks.tfvars
new file mode 100644
index 00000000..56799a75
--- /dev/null
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level2/aks_secure_baseline/aks.tfvars
@@ -0,0 +1,44 @@
+aks_cluster_key = "cluster_re1"
+aks_cluster_vnet_key = "vnet_aks_re1"
+
+aks_clusters = {
+ cluster_re1 = {
+ lz_key = "aks"
+ key = "cluster_re1"
+ }
+}
+vnets = {
+ vnet_aks_re1 = {
+ lz_key = "networking_spoke"
+ key = "vnet_aks_re1"
+ # subnet_keys = [
+ # "aks_nodepool_user1",
+ # "aks_ingress"
+ # ]
+ }
+}
+#
+# Reference to the AAD managed identities to register to the AKS cluster
+#
+managed_identities = {
+ ingress_msi = {
+ lz_key = "aks"
+ msi_keys = [
+ "ingress",
+ ]
+ }
+}
+namespaces = {
+ flux = {
+ name = "flux-system"
+ }
+}
+
+flux_settings = {
+ aks_secure_baseline = {
+ namespace = "flux-system"
+ url = "https://github.com/Azure/caf-terraform-landingzones-starter.git"
+ branch = "CSE-AKS-terratest"
+ target_path = "./enterprise_scale/construction_sets/aks/online/aks_secure_baseline/cluster-baseline-settings"
+ }
+}
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level2/aks_secure_baseline/landingzone.tfvars b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level2/aks_secure_baseline/landingzone.tfvars
new file mode 100644
index 00000000..c5964378
--- /dev/null
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/configuration/level2/aks_secure_baseline/landingzone.tfvars
@@ -0,0 +1,16 @@
+landingzone = {
+ backend_type = "azurerm"
+ global_settings_key = "aks"
+ level = "level2"
+ key = "aks_secure_baseline"
+ tfstates = {
+ aks = {
+ level = "current"
+ tfstate = "aks.tfstate"
+ }
+ networking_spoke = {
+ level = "lower"
+ tfstate = "networking_spoke.tfstate"
+ }
+ }
+}
\ No newline at end of file
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/docs/aks.md b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/docs/aks.md
new file mode 100644
index 00000000..5257c33f
--- /dev/null
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/landingzone/docs/aks.md
@@ -0,0 +1,206 @@
+# Deploy AKS Applications
+
+## Deploy cluster baseline settings via Flux
+
+Flux V2 and [infrastructure configurations](../../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 "*enterprise_scale/construction_sets/aks/online/aks_secure_baseline/*"
+If not use the below command:
+
+ ```bash
+ # Go to the AKS construction set folder
+ cd caf-terraform-landingzones-starter/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/
+ # If opened in containter in VSCode
+ cd /tf/caf/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/
+ ```
+
+ ```bash
+ output_file=/tf/caf/output.json
+
+ rover \
+ -lz /tf/caf/landingzones/caf_solution \
+ -tfstate aks.tfstate \
+ -env ${caf_env} \
+ -level level2 \
+ -a output -json -o $output_file
+
+ # To find a path to an output key
+ output_key="aks_kubeconfig_cmd"
+ cat $output_file | jq -c 'paths | select(.[-1] == "'"$output_key"'")'
+ # Login to the AKS in current user
+ cat $output_file | jq -r .objects.value.aks.aks_clusters.cluster_re1.aks_kubeconfig_cmd | bash
+
+ # If there is lack of RBAC permission in your user role, login with Admin (not recommended for Production)
+ cat $output_file | jq -r .objects.value.aks.aks_clusters.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](../../cluster-baseline-settings):
+
+- AAD Pod Identity
+- AKV Secret Store CSI Driver
+- Ingress Network Policy
+- Kured
+
+
+ ```bash
+ # Watch configurations deployment, Ctrl-C to quit
+ kubectl get pod -n cluster-baseline-settings -w
+ ```
+
+Flux pulls yamls from [cluster-baseline-settings](../../cluster-baseline-settings) and applies them to the cluster.
+If there is a need to change the folder to your own, please modify [cluster-baseline-settings.yaml](../flux/cluster-baseline-settings.yaml)
+
+## Deploy sample workload
+
+1. Get the AKS Ingress Controller Managed Identity details.
+
+ ```bash
+ export TRAEFIK_USER_ASSIGNED_IDENTITY_RESOURCE_ID=$(cat $output_file | jq -r .objects.value.aks.managed_identities.ingress.id)
+ export TRAEFIK_USER_ASSIGNED_IDENTITY_CLIENT_ID=$(cat $output_file | jq -r .objects.value.aks.managed_identities.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 < 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=$(cat $output_file | jq -r .objects.value.aks.keyvaults.secrets.name)
+ TENANTID_AZURERBAC=$(az account show --query tenantId -o tsv)
+ ```
+ ```yaml
+ cat < :warning: The user or service principal initiating the deployment process _must_ have the following minimal set of Azure Role-Based Access Control (RBAC) roles:
+ >
+ > * [Contributor role](https://docs.microsoft.com/azure/role-based-access-control/built-in-roles#contributor) is _required_ at the subscription level to have the ability to create resource groups and perform deployments.
+ > * [User Access Administrator role](https://docs.microsoft.com/azure/role-based-access-control/built-in-roles#user-access-administrator) is _required_ at the subscription level since you'll be granting least-privilege RBAC access to managed identities.
+ > * One such example is detailed in the [Container Insights documentation](https://docs.microsoft.com/azure/azure-monitor/insights/container-insights-troubleshoot#authorization-error-during-onboarding-or-update-operation).
+
+2. An Azure AD tenant to associate your Kubernetes RBAC configuration to.
+
+ > :warning: The user or service principal initiating the deployment process _must_ have the following minimal set of Azure AD permissions assigned:
+ >
+ > * Azure AD [User Administrator](https://docs.microsoft.com/azure/active-directory/users-groups-roles/directory-assign-admin-roles#user-administrator-permissions) is _required_ to create a "break glass" AKS admin Active Directory Security Group and User. Alternatively, you could get your Azure AD admin to create this for you when instructed to do so.
+ > * If you are not part of the User Administrator group in the tenant associated to your Azure subscription, please consider [creating a new tenant](https://docs.microsoft.com/azure/active-directory/fundamentals/active-directory-access-create-new-tenant#create-a-new-tenant-for-your-organization) to use while evaluating this implementation.
+
+3. If you opt for Azure Cloud Shell, you don't need to complete those steps and can jump on the next section (step 4). On Windows, you can use the Ubuntu on [Windows Subsystem for Linux](https://docs.microsoft.com/windows/wsl/about#what-is-wsl-2) to run Bash. Once your bash shell is up you will need to install these prerequisites.
+
+ Latest [Azure CLI installed](https://docs.microsoft.com/cli/azure/install-azure-cli?view=azure-cli-latest)
+
+ ```bash
+ sudo apt install azure-cli
+ ```
+
+ Terrafrom (Ubuntu) : For more information visit [here](https://learn.hashicorp.com/tutorials/terraform/install-cli)
+
+ ```bash
+ curl -fsSL https://apt.releases.hashicorp.com/gpg | sudo apt-key add -
+ sudo apt-add-repository "deb [arch=amd64] https://apt.releases.hashicorp.com $(lsb_release -cs) main"
+ sudo apt-get update && sudo apt-get install terraform
+ ```
+
+ jq : For more information visit [here](https://stedolan.github.io/jq/download/)
+
+ ```bash
+ sudo apt install jq
+ ```
+
+ kubectl: For more information visit [here](https://kubernetes.io/docs/tasks/tools/install-kubectl/)
+
+ ```bash
+ # kubectl:
+ curl -LO "https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"
+ sudo install -o root -g root -m 0755 kubectl /usr/local/bin/kubectl
+ ```
+
+4. Clone/download this repo locally, or even better fork this repository.
+
+ > :twisted_rightwards_arrows: If you have forked this reference implementation repo, you'll be able to customize some of the files and commands for a more personalized experience; also ensure references to repos mentioned are updated to use your own (e.g. the following `GITHUB_REPO`).
+
+ ```bash
+ export GITHUB_REPO=https://github.com/Azure/caf-terraform-landingzones-starter.git
+ git clone $GITHUB_REPO
+ ```
+
+
+# Next step
+
+:arrow_forward: [Deploy infrastructures using Terraform](docs/terraform.md)
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/add-ons/flux/flux.tf b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/add-ons/flux/flux.tf
new file mode 100644
index 00000000..b2ca6bb0
--- /dev/null
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/add-ons/flux/flux.tf
@@ -0,0 +1,5 @@
+module "flux_addon" {
+ source = "github.com/Azure/caf-terraform-landingzones//caf_solution/add-ons/aks_secure_baseline_v2/flux"
+ for_each = var.flux_settings
+ setting = each.value
+}
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/add-ons/flux/main.tf b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/add-ons/flux/main.tf
new file mode 100644
index 00000000..90705b54
--- /dev/null
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/add-ons/flux/main.tf
@@ -0,0 +1,20 @@
+terraform {
+ required_providers {
+ kubernetes = {
+ source = "hashicorp/kubernetes"
+ version = ">= 2.0.2"
+ }
+ kubectl = {
+ source = "gavinbunney/kubectl"
+ version = ">= 1.11.1"
+ }
+ flux = {
+ source = "fluxcd/flux"
+ version = ">= 0.2.0"
+ }
+ }
+ required_version = ">= 0.13"
+}
+
+
+
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/add-ons/flux/providers.tf b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/add-ons/flux/providers.tf
new file mode 100644
index 00000000..242f8edf
--- /dev/null
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/add-ons/flux/providers.tf
@@ -0,0 +1,29 @@
+provider "azurerm" {
+ features {
+ }
+}
+
+provider "kubectl" {
+ host = try(data.azurerm_kubernetes_cluster.kubeconfig.kube_admin_config.0.host, null)
+ username = try(data.azurerm_kubernetes_cluster.kubeconfig.kube_admin_config.0.username, null)
+ password = try(data.azurerm_kubernetes_cluster.kubeconfig.kube_admin_config.0.password, null)
+ client_key = try(base64decode(data.azurerm_kubernetes_cluster.kubeconfig.kube_admin_config.0.client_key), null)
+ client_certificate = try(base64decode(data.azurerm_kubernetes_cluster.kubeconfig.kube_admin_config.0.client_certificate), null)
+ cluster_ca_certificate = try(base64decode(data.azurerm_kubernetes_cluster.kubeconfig.kube_admin_config.0.cluster_ca_certificate), null)
+ load_config_file = false
+}
+
+provider "kubernetes" {
+ host = try(data.azurerm_kubernetes_cluster.kubeconfig.kube_admin_config.0.host, null)
+ username = try(data.azurerm_kubernetes_cluster.kubeconfig.kube_admin_config.0.username, null)
+ password = try(data.azurerm_kubernetes_cluster.kubeconfig.kube_admin_config.0.password, null)
+ client_key = try(base64decode(data.azurerm_kubernetes_cluster.kubeconfig.kube_admin_config.0.client_key), null)
+ client_certificate = try(base64decode(data.azurerm_kubernetes_cluster.kubeconfig.kube_admin_config.0.client_certificate), null)
+ cluster_ca_certificate = try(base64decode(data.azurerm_kubernetes_cluster.kubeconfig.kube_admin_config.0.cluster_ca_certificate), null)
+}
+
+# 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
+}
\ No newline at end of file
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/add-ons/flux/variables.tf b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/add-ons/flux/variables.tf
new file mode 100644
index 00000000..264b64b8
--- /dev/null
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/add-ons/flux/variables.tf
@@ -0,0 +1,7 @@
+variable "aks_clusters" {
+ default = {}
+}
+
+variable "aks_cluster_key" {}
+
+variable "flux_settings" {}
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/configuration/agw/agw.tfvars b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/configuration/agw/agw.tfvars
similarity index 100%
rename from enterprise_scale/construction_sets/aks/online/aks_secure_baseline/configuration/agw/agw.tfvars
rename to enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/configuration/agw/agw.tfvars
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/configuration/agw/agw_application.tfvars b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/configuration/agw/agw_application.tfvars
new file mode 100644
index 00000000..b8a24de1
--- /dev/null
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/configuration/agw/agw_application.tfvars
@@ -0,0 +1,54 @@
+application_gateway_applications = {
+ aspnetapp_az1_agw1 = {
+
+ name = "aspnetapp"
+ application_gateway_key = "agw1_az1"
+
+ 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"
+ }
+ }
+ }
+
+
+ request_routing_rules = {
+ default = {
+ rule_type = "Basic"
+ }
+ }
+
+ 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"]
+ }
+
+
+
+ backend_pool = {
+ fqdns = [
+ "bu0001a0008-00.aks-ingress.contoso.com"
+ ]
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/configuration/agw/domain.tfvars b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/configuration/agw/domain.tfvars
similarity index 100%
rename from enterprise_scale/construction_sets/aks/online/aks_secure_baseline/configuration/agw/domain.tfvars
rename to enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/configuration/agw/domain.tfvars
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/configuration/aks.tfvars b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/configuration/aks.tfvars
similarity index 86%
rename from enterprise_scale/construction_sets/aks/online/aks_secure_baseline/configuration/aks.tfvars
rename to enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/configuration/aks.tfvars
index ceb7d70e..177ab792 100644
--- a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/configuration/aks.tfvars
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/configuration/aks.tfvars
@@ -17,15 +17,20 @@ aks_clusters = {
type = "SystemAssigned"
}
- # kubernetes_version = "1.19.6"
+
+ # kubernetes_version = "1.20.5"
vnet_key = "vnet_aks_re1"
+ # network plugin and network policy should be "azure" (recommended by Secure AKS baseline)
network_profile = {
network_plugin = "azure"
load_balancer_sku = "Standard"
outbound_type = "userDefinedRouting"
}
+ # until the issue with Flux and Azure policy is resolved https://github.com/fluxcd/flux2/issues/703
+ #network_policy = "azure"
+
role_based_access_control = {
enabled = true
azure_active_directory = {
@@ -67,7 +72,7 @@ aks_clusters = {
node_count = 3
os_disk_type = "Ephemeral"
os_disk_size_gb = 80
- # orchestrator_version = "1.19.6"
+ # orchestrator_version = "1.20.5"
tags = {
"project" = "system services"
}
@@ -86,7 +91,7 @@ aks_clusters = {
os_disk_type = "Ephemeral"
enable_auto_scaling = false
os_disk_size_gb = 120
- # orchestrator_version = "1.19.6"
+ # orchestrator_version = "1.20.5"
tags = {
"project" = "user services"
}
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/configuration/bastion/bastion.ignore b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/configuration/bastion/bastion.ignore
similarity index 100%
rename from enterprise_scale/construction_sets/aks/online/aks_secure_baseline/configuration/bastion/bastion.ignore
rename to enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/configuration/bastion/bastion.ignore
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/configuration/global_settings.tfvars b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/configuration/global_settings.tfvars
similarity index 100%
rename from enterprise_scale/construction_sets/aks/online/aks_secure_baseline/configuration/global_settings.tfvars
rename to enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/configuration/global_settings.tfvars
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/configuration/iam/iam_aad.ignore b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/configuration/iam/iam_aad.ignore
similarity index 100%
rename from enterprise_scale/construction_sets/aks/online/aks_secure_baseline/configuration/iam/iam_aad.ignore
rename to enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/configuration/iam/iam_aad.ignore
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/configuration/iam/iam_managed_identities.tfvars b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/configuration/iam/iam_managed_identities.tfvars
new file mode 100644
index 00000000..4788561c
--- /dev/null
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/configuration/iam/iam_managed_identities.tfvars
@@ -0,0 +1,10 @@
+managed_identities = {
+ ingress = {
+ name = "podmi-ingress-controller"
+ resource_group_key = "devops_re1"
+ }
+ apgw_keyvault_secrets = {
+ name = "agw-secrets-msi"
+ resource_group_key = "devops_re1"
+ }
+}
\ No newline at end of file
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/configuration/iam/iam_role_mappings.tfvars b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/configuration/iam/iam_role_mappings.tfvars
new file mode 100644
index 00000000..1caefec4
--- /dev/null
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/configuration/iam/iam_role_mappings.tfvars
@@ -0,0 +1,19 @@
+#
+# Services supported: subscriptions, storage accounts and resource groups
+# Can assign roles to: AD groups, AD object ID, AD applications, Managed identities
+#
+role_mapping = {
+
+ built_in_role_mapping = {
+ keyvaults = {
+ secrets = {
+ "Contributor" = {
+ managed_identities = {
+ keys = ["ingress"]
+ }
+ } // "Contributor"
+ } // logged_in_subscription
+ } // subscriptions
+ } // built_in_role_mapping
+} // role_mapping
+
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/configuration/keyvault/certificate_requests.tfvars b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/configuration/keyvault/certificate_requests.tfvars
new file mode 100644
index 00000000..2c78de55
--- /dev/null
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/configuration/keyvault/certificate_requests.tfvars
@@ -0,0 +1,64 @@
+keyvault_certificate_requests = {
+
+ wildcard_ingress = {
+ name = "wildcard-ingress"
+ keyvault_key = "secrets"
+ certificate_policy = {
+ issuer_key_or_name = "self"
+ exportable = true
+ key_size = 4096 // value can be 2048, 3072 or 4096
+ key_type = "RSA"
+ reuse_key = false
+ renewal_action = "EmailContacts"
+ lifetime_percentage = 90
+ # days_before_expiry = 10
+ content_type = "application/x-pkcs12" // application/x-pem-file
+
+ x509_certificate_properties = {
+
+ # Refer to the documentation step to adjust the public dns domain name setup in internet_domain_name.tfvars
+ subject = "CN=*.aks-ingress.contoso.com"
+ validity_in_months = 12
+ key_usage = ["keyCertSign"]
+ subject_alternative_names = {
+ dns_names = []
+ emails = []
+ upns = []
+ }
+ }
+ }
+ }
+ appgateway = {
+ name = "appgateway"
+ keyvault_key = "secrets"
+ certificate_policy = {
+ issuer_key_or_name = "self"
+ exportable = true
+ key_size = 4096 // value can be 2048, 3072 or 4096
+ key_type = "RSA"
+ reuse_key = false
+ renewal_action = "EmailContacts"
+ lifetime_percentage = 90
+ # days_before_expiry = 10
+ content_type = "application/x-pkcs12" // application/x-pem-file
+
+ x509_certificate_properties = {
+
+ # Refer to the documentation step to adjust the public dns domain name setup in internet_domain_name.tfvars
+ # subject = "CN=*.aks-ingress.contoso.com"
+ domain_name_registration = {
+ # lz_key = ""
+ key = "random_domain"
+ # subdomain = "*"
+ }
+ validity_in_months = 12
+ key_usage = ["keyCertSign"]
+ subject_alternative_names = {
+ dns_names = []
+ emails = []
+ upns = []
+ }
+ }
+ }
+ }
+}
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/configuration/keyvault/keyvaults.tfvars b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/configuration/keyvault/keyvaults.tfvars
new file mode 100644
index 00000000..3b446634
--- /dev/null
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/configuration/keyvault/keyvaults.tfvars
@@ -0,0 +1,33 @@
+
+keyvaults = {
+
+ # This keyvault is used to store the complex password created for the AKS breakglass admin user
+ secrets = {
+ name = "secrets"
+ resource_group_key = "aks_re1"
+ region = "region1"
+ sku_name = "premium"
+ soft_delete_enabled = true
+
+ creation_policies = {
+ logged_in_user = {
+ # if the key is set to "logged_in_user" add the user running terraform in the keyvault policy
+ secret_permissions = ["Set", "Get", "List", "Delete", "Purge", "Recover"]
+ certificate_permissions = ["Create", "Get", "List", "Delete", "Purge", "Recover"]
+ }
+
+ ingress_msi = {
+ managed_identity_key = "ingress"
+ secret_permissions = ["Get"]
+ certificate_permissions = ["Get"]
+ }
+
+ apgw_keyvault_secrets = {
+ managed_identity_key = "apgw_keyvault_secrets"
+ certificate_permissions = ["Get"]
+ secret_permissions = ["Get"]
+ }
+
+ }
+ }
+}
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/configuration/monitor/diagnostics.tfvars b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/configuration/monitor/diagnostics.tfvars
new file mode 100644
index 00000000..f25e1eb9
--- /dev/null
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/configuration/monitor/diagnostics.tfvars
@@ -0,0 +1,35 @@
+diagnostics_definition = {
+ azure_container_registry = {
+ name = "operational_logs_and_metrics"
+ categories = {
+ log = [
+ # ["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period]
+ ["ContainerRegistryRepositoryEvents", true, false, 7],
+ ["ContainerRegistryLoginEvents", 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 = {
+ log = [
+ # ["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period]
+ ["kube-apiserver", true, false, 7],
+ ["kube-audit", false, false, 0],
+ ["kube-audit-admin", true, false, 7],
+ ["kube-controller-manager", true, false, 7],
+ ["kube-scheduler", false, false, 0],
+ ["cluster-autoscaler", true, false, 7],
+ ["guard", true, false, 7],
+ ]
+ metric = [
+ #["Category name", "Diagnostics Enabled(true/false)", "Retention Enabled(true/false)", Retention_period]
+ ["AllMetrics", true, false, 7],
+ ]
+ }
+ }
+}
\ No newline at end of file
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/configuration/monitor/log_analytics.tfvars b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/configuration/monitor/log_analytics.tfvars
new file mode 100644
index 00000000..2ef6d739
--- /dev/null
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/configuration/monitor/log_analytics.tfvars
@@ -0,0 +1,17 @@
+diagnostic_log_analytics = {
+ central_logs_region1 = {
+ region = "region1"
+ name = "logs"
+ resource_group_key = "ops_re1"
+ }
+}
+
+diagnostics_destinations = {
+ # Storage keys must reference the azure region name
+ log_analytics = {
+ central_logs = {
+ log_analytics_key = "central_logs_region1"
+ log_analytics_destination_type = "Dedicated"
+ }
+ }
+}
\ No newline at end of file
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/configuration/networking/firewall_application_rule_collection_definition.tfvars b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/configuration/networking/firewall_application_rule_collection_definition.tfvars
new file mode 100644
index 00000000..91662f18
--- /dev/null
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/configuration/networking/firewall_application_rule_collection_definition.tfvars
@@ -0,0 +1,138 @@
+azurerm_firewall_application_rule_collection_definition = {
+ aks = {
+ name = "aks"
+ action = "Allow"
+ priority = 100
+ ruleset = {
+ aks = {
+ name = "aks"
+ # source_addresses = [
+ # "*",
+ # ]
+ source_ip_groups_keys = [
+ "aks_ip_group1"
+ ]
+ fqdn_tags = [
+ "AzureKubernetesService",
+ ]
+ },
+ }
+ }
+ packages = {
+ name = "packages"
+ action = "Allow"
+ priority = 110
+ ruleset = {
+ ubuntu = {
+ name = "ubuntu"
+ # source_addresses = [
+ # "*",
+ # ]
+ source_ip_groups_keys = [
+ "aks_ip_group1"
+ ]
+ target_fqdns = [
+ "security.ubuntu.com",
+ "azure.archive.ubuntu.com",
+ "archive.ubuntu.com",
+ "changelogs.ubuntu.com",
+ ]
+ protocol = {
+ https = {
+ port = "443"
+ type = "Https"
+ }
+ http = {
+ port = "80"
+ type = "Http"
+ }
+ }
+ },
+ docker = {
+ name = "docker"
+ # source_addresses = [
+ # "*",
+ # ]
+ source_ip_groups_keys = [
+ "aks_ip_group1"
+ ]
+ target_fqdns = [
+ "download.docker.com", # Docker
+ "*.docker.io", # Docker images
+ "*.docker.com" # Docker registry
+ ]
+ protocol = {
+ http = {
+ port = "443"
+ type = "Https"
+ }
+ }
+ },
+ tools = {
+ name = "tools"
+ # source_addresses = [
+ # "*",
+ # ]
+ source_ip_groups_keys = [
+ "aks_ip_group1"
+ ]
+ target_fqdns = [
+ "packages.microsoft.com",
+ "azurecliprod.blob.core.windows.net", # Azure cli
+ "packages.cloud.google.com", # kubectl
+ "apt.kubernetes.io", # Ubuntu packages for kubectl
+ "*.snapcraft.io", # snap to install kubectl
+ ]
+ protocol = {
+ http = {
+ port = "443"
+ type = "Https"
+ }
+ }
+ },
+ github = {
+ name = "github"
+ # source_addresses = [
+ # "*",
+ # ]
+ source_ip_groups_keys = [
+ "aks_ip_group1"
+ ]
+ target_fqdns = [
+ "api.github.com",
+ "ghcr.io",
+ "*.ghcr.io",
+ "github.com",
+ "*.githubusercontent.com",
+ "charts.bitnami.com"
+ ]
+ protocol = {
+ http = {
+ port = "443"
+ type = "Https"
+ }
+ }
+ },
+ mcr = {
+ name = "mcr"
+ # source_addresses = [
+ # "*",
+ # ]
+
+ source_ip_groups_keys = [
+ "aks_ip_group1"
+ ]
+
+ target_fqdns = [
+ "*.data.mcr.microsoft.com",
+ ]
+ protocol = {
+ http = {
+ port = "443"
+ type = "Https"
+ }
+ }
+ },
+ }
+ }
+}
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/configuration/networking/firewall_network_rule_collection_definition.tfvars b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/configuration/networking/firewall_network_rule_collection_definition.tfvars
new file mode 100644
index 00000000..b46ce24a
--- /dev/null
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/configuration/networking/firewall_network_rule_collection_definition.tfvars
@@ -0,0 +1,82 @@
+
+azurerm_firewall_network_rule_collection_definition = {
+ aks = {
+ name = "aks"
+ action = "Allow"
+ priority = 150
+ ruleset = {
+ ntp = {
+ name = "ntp"
+ # source_addresses = [
+ # "*",
+ # ]
+ source_ip_groups_keys = [
+ "aks_ip_group1"
+ ]
+ destination_ports = [
+ "123",
+ ]
+ destination_addresses = [
+ "*"
+ ]
+ protocols = [
+ "UDP",
+ ]
+ },
+ monitor = {
+ name = "monitor"
+ # source_addresses = [
+ # "*",
+ # ]
+ source_ip_groups_keys = [
+ "aks_ip_group1"
+ ]
+ destination_ports = [
+ "443",
+ ]
+ destination_addresses = [
+ "AzureMonitor"
+ ]
+ protocols = [
+ "TCP",
+ ]
+ },
+ apiservertcp = {
+ name = "apiservertcp"
+ # source_addresses = [
+ # "*",
+ # ]
+ source_ip_groups_keys = [
+ "aks_ip_group1"
+ ]
+ destination_ports = [
+ "443", "9000", "22"
+ ]
+ destination_addresses = [
+ "AzureCloud"
+ ]
+ protocols = [
+ "TCP",
+ ]
+ },
+ apiserverudp = {
+ name = "apiserverudp"
+ # source_addresses = [
+ # "*",
+ # ]
+ source_ip_groups_keys = [
+ "aks_ip_group1"
+ ]
+ destination_ports = [
+ "1194"
+ ]
+ destination_addresses = [
+ "AzureCloud"
+ ]
+ protocols = [
+ "UDP",
+ ]
+ },
+ }
+ }
+}
\ No newline at end of file
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/configuration/networking/firewalls.tfvars b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/configuration/networking/firewalls.tfvars
new file mode 100644
index 00000000..0aae8605
--- /dev/null
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/configuration/networking/firewalls.tfvars
@@ -0,0 +1,20 @@
+azurerm_firewalls = {
+ fw_re1 = {
+ name = "egress"
+ resource_group_key = "vnet_hub_re1"
+ vnet_key = "vnet_hub_re1"
+ # public_ip_key = "firewall_re1" # if this is defined, public_ip_keys is ignored
+ public_ip_keys = ["firewall_re1", "firewall_pip2_re1"]
+
+ azurerm_firewall_network_rule_collections = [
+ "aks"
+ ]
+
+ azurerm_firewall_application_rule_collections = [
+ "aks",
+ "packages"
+ ]
+ }
+}
+
+
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/configuration/networking/ip_groups.tfvars b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/configuration/networking/ip_groups.tfvars
similarity index 100%
rename from enterprise_scale/construction_sets/aks/online/aks_secure_baseline/configuration/networking/ip_groups.tfvars
rename to enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/configuration/networking/ip_groups.tfvars
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/configuration/networking/networking.tfvars b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/configuration/networking/networking.tfvars
similarity index 100%
rename from enterprise_scale/construction_sets/aks/online/aks_secure_baseline/configuration/networking/networking.tfvars
rename to enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/configuration/networking/networking.tfvars
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/configuration/networking/nsg.tfvars b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/configuration/networking/nsg.tfvars
new file mode 100644
index 00000000..04807d8c
--- /dev/null
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/configuration/networking/nsg.tfvars
@@ -0,0 +1,385 @@
+
+#
+# Definition of the networking security groups
+#
+network_security_group_definition = {
+ # This entry is applied to all subnets with no NSG defined
+ azure_kubernetes_cluster_nsg = {
+ nsg = [
+
+ ]
+ }
+ azure_bastion_nsg = {
+ nsg = [
+ {
+ name = "in-allow-https",
+ priority = "120"
+ direction = "Inbound"
+ access = "Allow"
+ protocol = "tcp"
+ source_port_range = "*"
+ destination_port_range = "443"
+ source_address_prefix = "Internet"
+ destination_address_prefix = "*"
+ },
+ {
+ name = "in-allow-gateway-manager",
+ priority = "130"
+ direction = "Inbound"
+ access = "Allow"
+ protocol = "tcp"
+ source_port_range = "*"
+ destination_port_range = "443"
+ source_address_prefix = "GatewayManager"
+ destination_address_prefix = "*"
+ },
+ {
+ name = "in-allow-load-balancer",
+ priority = "140"
+ direction = "Inbound"
+ access = "Allow"
+ protocol = "tcp"
+ source_port_range = "*"
+ destination_port_range = "443"
+ source_address_prefix = "AzureLoadBalancer"
+ destination_address_prefix = "*"
+ },
+ {
+ name = "in-allow-bastion-host-communication-8080",
+ priority = "150"
+ direction = "Inbound"
+ access = "Allow"
+ protocol = "*"
+ source_port_range = "*"
+ destination_port_range = "8080"
+ source_address_prefix = "VirtualNetwork"
+ destination_address_prefix = "VirtualNetwork"
+ },
+ {
+ name = "in-allow-bastion-host-communication-5701",
+ priority = "151"
+ direction = "Inbound"
+ access = "Allow"
+ protocol = "*"
+ source_port_range = "*"
+ destination_port_range = "5701"
+ source_address_prefix = "VirtualNetwork"
+ destination_address_prefix = "VirtualNetwork"
+ },
+ {
+ name = "out-vnet-allow-22",
+ priority = "100"
+ direction = "Outbound"
+ access = "Allow"
+ protocol = "*"
+ source_port_range = "*"
+ destination_port_range = "22"
+ source_address_prefix = "*"
+ destination_address_prefix = "VirtualNetwork"
+ },
+ {
+ name = "out-vnet-allow-3389",
+ priority = "101"
+ direction = "Outbound"
+ access = "Allow"
+ protocol = "*"
+ source_port_range = "*"
+ destination_port_range = "3389"
+ source_address_prefix = "*"
+ destination_address_prefix = "VirtualNetwork"
+ },
+ {
+ name = "out-azure-cloud-allow-3389",
+ priority = "110"
+ direction = "Outbound"
+ access = "Allow"
+ protocol = "tcp"
+ source_port_range = "*"
+ destination_port_range = "443"
+ source_address_prefix = "*"
+ destination_address_prefix = "AzureCloud"
+ },
+ {
+ name = "out-communication-allow-8080",
+ priority = "120"
+ direction = "Outbound"
+ access = "Allow"
+ protocol = "tcp"
+ source_port_range = "*"
+ destination_port_range = "8080"
+ source_address_prefix = "VirtualNetwork"
+ destination_address_prefix = "VirtualNetwork"
+ },
+ {
+ name = "out-communication-allow-5701",
+ priority = "121"
+ direction = "Outbound"
+ access = "Allow"
+ protocol = "tcp"
+ source_port_range = "*"
+ destination_port_range = "5701"
+ source_address_prefix = "VirtualNetwork"
+ destination_address_prefix = "VirtualNetwork"
+ },
+ {
+ name = "out-gateway-information-allow",
+ priority = "130"
+ direction = "Outbound"
+ access = "Allow"
+ protocol = "*"
+ source_port_range = "*"
+ destination_port_range = "80"
+ source_address_prefix = "*"
+ destination_address_prefix = "Internet"
+ }
+ ]
+ }
+
+ application_gateway = {
+ nsg = [
+ {
+ name = "Inbound-HTTP",
+ priority = "120"
+ direction = "Inbound"
+ access = "Allow"
+ protocol = "*"
+ source_port_range = "*"
+ destination_port_range = "80-82"
+ source_address_prefix = "*"
+ destination_address_prefix = "*"
+ },
+ {
+ name = "Inbound-HTTPs",
+ priority = "130"
+ direction = "Inbound"
+ access = "Allow"
+ protocol = "*"
+ source_port_range = "*"
+ destination_port_range = "443"
+ source_address_prefix = "*"
+ destination_address_prefix = "*"
+ },
+ {
+ name = "Inbound-AGW",
+ priority = "140"
+ direction = "Inbound"
+ access = "Allow"
+ protocol = "*"
+ source_port_range = "*"
+ destination_port_range = "65200-65535"
+ source_address_prefix = "*"
+ destination_address_prefix = "*"
+ },
+ ]
+ }
+
+ api_management = {
+
+ nsg = [
+ {
+ name = "Inbound-APIM",
+ priority = "100"
+ direction = "Inbound"
+ access = "Allow"
+ protocol = "tcp"
+ source_port_range = "*"
+ destination_port_range = "3443"
+ source_address_prefix = "ApiManagement"
+ destination_address_prefix = "VirtualNetwork"
+ },
+ {
+ name = "Inbound-Redis",
+ priority = "110"
+ direction = "Inbound"
+ access = "Allow"
+ protocol = "tcp"
+ source_port_range = "*"
+ destination_port_range = "6381-6383"
+ source_address_prefix = "VirtualNetwork"
+ destination_address_prefix = "VirtualNetwork"
+ },
+ {
+ name = "Inbound-LoadBalancer",
+ priority = "120"
+ direction = "Inbound"
+ access = "Allow"
+ protocol = "tcp"
+ source_port_range = "*"
+ destination_port_range = "*"
+ source_address_prefix = "AzureLoadBalancer"
+ destination_address_prefix = "VirtualNetwork"
+ },
+ {
+ name = "Outbound-StorageHttp",
+ priority = "100"
+ direction = "Outbound"
+ access = "Allow"
+ protocol = "tcp"
+ source_port_range = "*"
+ destination_port_range = "80"
+ source_address_prefix = "VirtualNetwork"
+ destination_address_prefix = "Storage"
+ },
+ {
+ name = "Outbound-StorageHttps",
+ priority = "110"
+ direction = "Outbound"
+ access = "Allow"
+ protocol = "tcp"
+ source_port_range = "*"
+ destination_port_range = "443"
+ source_address_prefix = "VirtualNetwork"
+ destination_address_prefix = "Storage"
+ },
+ {
+ name = "Outbound-AADHttp",
+ priority = "120"
+ direction = "Outbound"
+ access = "Allow"
+ protocol = "tcp"
+ source_port_range = "*"
+ destination_port_range = "80"
+ source_address_prefix = "VirtualNetwork"
+ destination_address_prefix = "AzureActiveDirectory"
+ },
+ {
+ name = "Outbound-AADHttps",
+ priority = "130"
+ direction = "Outbound"
+ access = "Allow"
+ protocol = "tcp"
+ source_port_range = "*"
+ destination_port_range = "443"
+ source_address_prefix = "VirtualNetwork"
+ destination_address_prefix = "AzureActiveDirectory"
+ },
+ {
+ name = "Outbound-SQL",
+ priority = "140"
+ direction = "Outbound"
+ access = "Allow"
+ protocol = "tcp"
+ source_port_range = "*"
+ destination_port_range = "1433"
+ source_address_prefix = "VirtualNetwork"
+ destination_address_prefix = "SQL"
+ },
+ {
+ name = "Outbound-EventHub",
+ priority = "150"
+ direction = "Outbound"
+ access = "Allow"
+ protocol = "tcp"
+ source_port_range = "*"
+ destination_port_range = "5671-5672"
+ source_address_prefix = "VirtualNetwork"
+ destination_address_prefix = "EventHub"
+ },
+ {
+ name = "Outbound-EventHubHttps",
+ priority = "160"
+ direction = "Outbound"
+ access = "Allow"
+ protocol = "tcp"
+ source_port_range = "*"
+ destination_port_range = "443"
+ source_address_prefix = "VirtualNetwork"
+ destination_address_prefix = "EventHub"
+ },
+ {
+ name = "Outbound-FileShareGit",
+ priority = "170"
+ direction = "Outbound"
+ access = "Allow"
+ protocol = "tcp"
+ source_port_range = "*"
+ destination_port_range = "445"
+ source_address_prefix = "VirtualNetwork"
+ destination_address_prefix = "Storage"
+ },
+ {
+ name = "Outbound-Health",
+ priority = "180"
+ direction = "Outbound"
+ access = "Allow"
+ protocol = "tcp"
+ source_port_range = "*"
+ destination_port_range = "1886"
+ source_address_prefix = "VirtualNetwork"
+ destination_address_prefix = "INTERNET"
+ },
+ {
+ name = "Outbound-Monitor",
+ priority = "190"
+ direction = "Outbound"
+ access = "Allow"
+ protocol = "tcp"
+ source_port_range = "*"
+ destination_port_range = "443"
+ source_address_prefix = "VirtualNetwork"
+ destination_address_prefix = "AzureMonitor"
+ },
+ {
+ name = "Outbound-MoSMTP1itor",
+ priority = "200"
+ direction = "Outbound"
+ access = "Allow"
+ protocol = "tcp"
+ source_port_range = "*"
+ destination_port_range = "25"
+ source_address_prefix = "VirtualNetwork"
+ destination_address_prefix = "INTERNET"
+ },
+ {
+ name = "Outbound-SMTP2",
+ priority = "210"
+ direction = "Outbound"
+ access = "Allow"
+ protocol = "tcp"
+ source_port_range = "*"
+ destination_port_range = "587"
+ source_address_prefix = "VirtualNetwork"
+ destination_address_prefix = "INTERNET"
+ },
+ {
+ name = "Outbound-SMTP3",
+ priority = "220"
+ direction = "Outbound"
+ access = "Allow"
+ protocol = "tcp"
+ source_port_range = "*"
+ destination_port_range = "25028"
+ source_address_prefix = "VirtualNetwork"
+ destination_address_prefix = "INTERNET"
+ },
+ {
+ name = "Outbound-Redis",
+ priority = "230"
+ direction = "Outbound"
+ access = "Allow"
+ protocol = "tcp"
+ source_port_range = "*"
+ destination_port_range = "6381-6383"
+ source_address_prefix = "VirtualNetwork"
+ destination_address_prefix = "VirtualNetwork"
+ },
+ ]
+ }
+
+ jumpbox = {
+ nsg = [
+ {
+ name = "ssh-inbound-22",
+ priority = "200"
+ direction = "Inbound"
+ access = "Allow"
+ protocol = "tcp"
+ source_port_range = "*"
+ destination_port_range = "22"
+ source_address_prefix = "*"
+ destination_address_prefix = "VirtualNetwork"
+ },
+ ]
+ }
+
+}
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/configuration/networking/peerings.tfvars b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/configuration/networking/peerings.tfvars
similarity index 100%
rename from enterprise_scale/construction_sets/aks/online/aks_secure_baseline/configuration/networking/peerings.tfvars
rename to enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/configuration/networking/peerings.tfvars
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/configuration/networking/private_dns.tfvars b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/configuration/networking/private_dns.tfvars
new file mode 100644
index 00000000..b7e5332f
--- /dev/null
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/configuration/networking/private_dns.tfvars
@@ -0,0 +1,24 @@
+
+private_dns = {
+ dns1 = {
+ name = "aks-ingress.contoso.com"
+ resource_group_key = "aks_spoke_re1"
+
+ records = {
+ a_records = {
+ ingress = {
+ name = "bu0001a0008-00"
+ ttl = 3600
+ records = ["10.100.82.10"]
+ }
+ }
+ }
+
+ vnet_links = {
+ link_aks = {
+ name = "aks-vnet-link"
+ vnet_key = "vnet_aks_re1"
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/configuration/networking/public_ips.tfvars b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/configuration/networking/public_ips.tfvars
similarity index 100%
rename from enterprise_scale/construction_sets/aks/online/aks_secure_baseline/configuration/networking/public_ips.tfvars
rename to enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/configuration/networking/public_ips.tfvars
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/configuration/networking/route_tables.tfvars b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/configuration/networking/route_tables.tfvars
similarity index 100%
rename from enterprise_scale/construction_sets/aks/online/aks_secure_baseline/configuration/networking/route_tables.tfvars
rename to enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/configuration/networking/route_tables.tfvars
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/configuration/resource_groups.tfvars b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/configuration/resource_groups.tfvars
similarity index 100%
rename from enterprise_scale/construction_sets/aks/online/aks_secure_baseline/configuration/resource_groups.tfvars
rename to enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/configuration/resource_groups.tfvars
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/configuration/workloads/flux.tfvars b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/configuration/workloads/flux.tfvars
new file mode 100644
index 00000000..4931ebca
--- /dev/null
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/configuration/workloads/flux.tfvars
@@ -0,0 +1,10 @@
+aks_cluster_key = "cluster_re1"
+
+flux_settings = {
+ aks_secure_baseline = {
+ namespace = "flux-system"
+ url = "https://github.com/Azure/caf-terraform-landingzones-starter.git"
+ branch = "CSE-AKS-terratest"
+ target_path = "./enterprise_scale/construction_sets/aks/online/aks_secure_baseline/cluster-baseline-settings/flux"
+ }
+}
\ No newline at end of file
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/02-aks.md b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/docs/aks.md
similarity index 65%
rename from enterprise_scale/construction_sets/aks/online/aks_secure_baseline/02-aks.md
rename to enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/docs/aks.md
index 4391a9cf..8c9ac9f1 100644
--- a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/02-aks.md
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/docs/aks.md
@@ -2,20 +2,32 @@
## Deploy cluster baseline settings via Flux
-Make sure the current folder is "*enterprise_scale/construction_sets/aks*"
+Flux V2 and [infrastructure configurations](../../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 "*enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone*"
+If not use the below command:
```bash
- # Login to the AKS if in ESLZ
+ # Go to the AKS construction set standalone folder
+ cd caf-terraform-landingzones-starter/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone
+ # If opened in containter in VSCode
+ cd /tf/caf/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone
+ ```
+
+ ```bash
+ # Login to the AKS in current user
echo $(terraform output -json | jq -r .aks_clusters_kubeconfig.value.cluster_re1.aks_kubeconfig_cmd) | bash
- # Otherwise use this to login
+ # 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](./cluster-baseline-settings):
+Please review the Baseline components that are deployed at [cluster-baseline-settings](../../cluster-baseline-settings):
- AAD Pod Identity
- AKV Secret Store CSI Driver
@@ -23,14 +35,12 @@ Please review the Baseline components that are deployed at [cluster-baseline-set
- Kured
```bash
- # Deploy Baseline components via Flux
- kubectl apply -f online/aks_secure_baseline/cluster-baseline-settings/flux.yaml
- # Watch Flux deployment, Ctrl-C to quit
- kubectl get po -n cluster-baseline-settings -w
+ # Watch configurations deployment, Ctrl-C to quit
+ kubectl get pod -n cluster-baseline-settings -w
```
-Flux will pull from [cluster-baseline-settings](./cluster-baseline-settings) and synchronize the folder to AKS.
-If there is a need to change the folder to your own folk, please modify [flux.yaml](cluster-baseline-settings/flux.yaml) --git-url args
+Flux pulls yamls from [cluster-baseline-settings](../../cluster-baseline-settings) and applies them to the cluster.
+If there is a need to change the folder to your own, please modify [cluster-baseline-settings.yaml](../flux/cluster-baseline-settings.yaml)
## Deploy sample workload
@@ -109,6 +119,7 @@ If there is a need to change the folder to your own folk, please modify [flux.ya
objectType: secret
tenantId: $TENANTID_AZURERBAC
EOF
+ ```
2. Update Traefik config to pin IP in Aks-ingress Subnet:
```bash
@@ -116,16 +127,17 @@ If there is a need to change the folder to your own folk, please modify [flux.ya
ingress_subnet_name=$(terraform output -json | jq -r .vnets.value.vnet_aks_re1.subnets.aks_ingress.name)
# Update the traefik yaml
# Mac UNIX:
- sed -i "" "s/azure-load-balancer-internal-subnet:.*/azure-load-balancer-internal-subnet:\ ${ingress_subnet_name}/g" online/aks_secure_baseline/workloads/baseline/traefik.yaml
+ sed -i "" "s/azure-load-balancer-internal-subnet:.*/azure-load-balancer-internal-subnet:\ ${ingress_subnet_name}/g" ../workloads/baseline/traefik.yaml
# Linux:
- sed -i "s/azure-load-balancer-internal-subnet:.*/azure-load-balancer-internal-subnet:\ ${ingress_subnet_name}/g" online/aks_secure_baseline/workloads/baseline/traefik.yaml
+ sed -i "s/azure-load-balancer-internal-subnet:.*/azure-load-balancer-internal-subnet:\ ${ingress_subnet_name}/g" ../workloads/baseline/traefik.yaml
```
3. Deploy Traefik & ASP.net sample appplication
+
```bash
- kubectl apply -f online/aks_secure_baseline/workloads/baseline
- # It takes 2-3 mins to deploy Traefik & the sample app. Watch all pods to be provision with:
+ kubectl apply -f ../workloads/baseline
+ # 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
@@ -136,13 +148,41 @@ If there is a need to change the folder to your own folk, please modify [flux.ya
4. You can now test the application from a browser. After couple of the minutes the application gateway health check warning should disappear
+
+## Test
+
+You may use [automated integration tests](../../test) to test the deployed infrastructure.
+
+You are done with deployment of AKS environment, next step is to deploy the application and reference components.
+
+```bash
+export ARM_SUBSCRIPTION_ID=$(az account show --query id -o tsv)
+export PREFIX=$(terraform output -json | jq -r '.global_settings.value.prefixes[0]')
+export ENVIRONMENT=sandpit # replace if another Environment was set in the rover, default is sandpit
+echo $(terraform output -json | jq -r .aks_clusters_kubeconfig.value.cluster_re1.aks_kubeconfig_admin_cmd) | bash
+
+# Go to the Test folder
+cd ../test
+
+go mod tidy
+
+# If there is ERROR: AADSTS70043: The refresh token has expired or is invalid due to sign-in frequency checks by conditional access
+# Perform az login again
+
+go test -v shared_services/shared_services_test.go
+go test -v aks/aks_test.go
+go test -v flux/flux_test.go
+```
+
## Destroy resources
When finished, please destroy all deployments with:
```bash
+# Go to the Standalone folder
+cd ../standalone
# Delete sample application, this contains PodDisruptionBudget that will block Terraform destroy
-kubectl delete -f online/aks_secure_baseline/workloads/baseline
+kubectl delete -f ../workloads/baseline
# (When needed) Destroy the resources
eval terraform destroy ${parameter_files}
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/docs/terraform.md b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/docs/terraform.md
new file mode 100644
index 00000000..96cb7932
--- /dev/null
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/docs/terraform.md
@@ -0,0 +1,70 @@
+# Deployment of Enterprise-Scale AKS Construction Set
+
+This reference implementation of AKS Secure Baseline Architecture within Enterprise Scale environment is built on CAF Terraform Landing zone framework composition.
+
+The following components will be deployed by the Enterprise-Scale AKS Construction Set. You can review each component as described below:
+
+![aks_enterprise_scale_lz](../../pictures/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 |
+||**Identity & Access Management**
||
+| Identity & Access Management | [iam_aad.tfvars](../configuration/iam/iam_aad.tfvars)
[iam_managed_identities.tfvars](../configuration/iam/iam_managed_identities.tfvars)
[iam_role_mappings.tfvars](../configuration/iam/iam_role_mappings.tfvars)| AAD admin group, User Managed Identities & Role Assignments |
+||**Gateway**
||
+| Application Gateway | [agw.tfvars](../configuration/agw/agw.tfvars)
[agw_application.tfvars](../configuration/agw/agw_application.tfvars)
| 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 |
+||**Networking**
||
+| Virtual networks | [networking.tfvars](../configuration/networking/networking.tfvars)
[peerings.tfvars](../configuration/networking/peerings.tfvars)
[nsg.tfvars](../configuration/networking/nsg.tfvars)
[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)
[firewall_application_rule_collection_definition.tfvars](../configuration/networking/firewall_application_rule_collection_definition.tfvars)
[firewall_network_rule_collection_definition.tfvars](../configuration/networking/firewall_network_rule_collection_definition.tfvars)
[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 |
+||**Security & Monitoring**
||
+| Azure Key Vault| [keyvaults.tfvars](../configuration/keyvault/keyvaults.tfvars)
[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)
[log_analytics.tfvars](../configuration/monitor/log_analytics.tfvars) | Diagnostics settings, Log Analytics Workspace for AKS logs & Prometheus metrics |
+||**Bastion**
||
+| Azure Bastion (OPTIONAL) | [bastion.tfvars](../configuration/bastion/bastion.ignore) | Azure Bastion Host & Windows VM to view aspnetsample website internally. |
+
+
+
+## Deployment
+
+```bash
+# Script to execute from bash shell
+
+# Login to your Azure Active Directory tenant
+az login -t {TENANTNID}
+
+# Make sure you are using the right subscription
+az account show -o table
+
+# If you are not in the correct subscription, change it substituting SUBSCRIPTIONID with the proper subscription id
+az account set --subscription {SUBSCRIPTIONID}
+
+# If you are running in Azure Cloud Shell, you need to run the following additional command:
+# export TF_VAR_logged_user_objectId=$(az ad signed-in-user show --query objectId -o tsv)
+```
+Set the folder to Standalone
+```bash
+# Go to the AKS construction set standalone folder
+cd caf-terraform-landingzones-starter/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/
+# If opened in containter in VSCode
+cd enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/
+```
+Deploy with Terraform
+```bash
+
+# Define the configuration files to apply, all tfvars files within the above folder recursively except for launchpad subfolder which is not relevant for this standalone guide
+parameter_files=$(find configuration -not -path "*launchpad*" | grep .tfvars | sed 's/.*/-var-file &/' | xargs)
+
+# Load the CAF module and related providers
+terraform init -upgrade
+
+# Trigger the deployment of the resources
+eval terraform apply ${parameter_files}
+```
+## Next step
+
+:arrow_forward: [Deploy sample workload into AKS](./aks.md)
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/flux.tf b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/flux.tf
new file mode 100644
index 00000000..a328c0a6
--- /dev/null
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/flux.tf
@@ -0,0 +1,6 @@
+module "flux_addon" {
+ source = "./add-ons/flux"
+ flux_settings = var.flux_settings
+ aks_clusters = module.caf.aks_clusters
+ aks_cluster_key = var.aks_cluster_key
+}
diff --git a/enterprise_scale/construction_sets/aks/main.tf b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/main.tf
similarity index 68%
rename from enterprise_scale/construction_sets/aks/main.tf
rename to enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/main.tf
index cfee07d4..15d1781e 100644
--- a/enterprise_scale/construction_sets/aks/main.tf
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/main.tf
@@ -32,15 +32,33 @@ terraform {
source = "aztfmod/azurecaf"
version = "~> 1.2.0"
}
+ kubernetes = {
+ source = "hashicorp/kubernetes"
+ version = ">= 2.0.2"
+ }
+ kubectl = {
+ source = "gavinbunney/kubectl"
+ version = ">= 1.11.1"
+ }
+ flux = {
+ source = "fluxcd/flux"
+ version = ">= 0.0.14"
+ }
}
required_version = ">= 0.13"
+
+
+ # comment it out for the local backend experience
+ # backend "azurerm" {}
}
provider "azurerm" {
+ partner_id = "451dc593-a3a3-4d41-91e7-3aadf93e1a78"
features {
key_vault {
purge_soft_delete_on_destroy = true
}
}
}
+
diff --git a/enterprise_scale/construction_sets/aks/module.tf b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/module.tf
similarity index 88%
rename from enterprise_scale/construction_sets/aks/module.tf
rename to enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/module.tf
index 5b9181b9..0b424ba0 100644
--- a/enterprise_scale/construction_sets/aks/module.tf
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/module.tf
@@ -1,17 +1,19 @@
module "caf" {
source = "aztfmod/caf/azurerm"
- version = "~> 5.3.0"
+ version = "~> 5.4.0"
- global_settings = var.global_settings
+ global_settings = merge((var.override_prefix == "" ? {} : { prefix = var.override_prefix }), var.global_settings)
logged_user_objectId = var.logged_user_objectId
tags = var.tags
resource_groups = var.resource_groups
- azuread_apps = var.azuread_apps
- azuread_users = var.azuread_users
- azuread_groups = var.azuread_groups
keyvaults = var.keyvaults
managed_identities = var.managed_identities
role_mapping = var.role_mapping
+ azuread = {
+ azuread_apps = var.azuread_apps
+ azuread_users = var.azuread_users
+ azuread_groups = var.azuread_groups
+ }
networking = {
application_gateways = var.application_gateways
@@ -48,4 +50,5 @@ module "caf" {
security = {
keyvault_certificate_requests = var.keyvault_certificate_requests
}
+
}
diff --git a/enterprise_scale/construction_sets/aks/output.tf b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/output.tf
similarity index 92%
rename from enterprise_scale/construction_sets/aks/output.tf
rename to enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/output.tf
index d8520819..97227c2c 100644
--- a/enterprise_scale/construction_sets/aks/output.tf
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/output.tf
@@ -34,3 +34,7 @@ output "vnets" {
output "azurerm_firewalls" {
value = module.caf.azurerm_firewalls
}
+
+output "global_settings" {
+ value = module.caf.global_settings
+}
\ No newline at end of file
diff --git a/enterprise_scale/construction_sets/aks/podidentity-assignment.tf b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/podidentity-assignment.tf
similarity index 96%
rename from enterprise_scale/construction_sets/aks/podidentity-assignment.tf
rename to enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/podidentity-assignment.tf
index 729e11e8..b9b9eed2 100644
--- a/enterprise_scale/construction_sets/aks/podidentity-assignment.tf
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/podidentity-assignment.tf
@@ -34,4 +34,4 @@ resource "azurerm_role_assignment" "kubelet_vnet_networkcontrib" {
role_definition_name = "Network Contributor"
principal_id = each.value.identity[0].principal_id
}
-# consider to narrow to ingress & nodepoll subnets
\ No newline at end of file
+# consider to narrow to ingress & nodepool subnets
\ No newline at end of file
diff --git a/enterprise_scale/construction_sets/aks/variables.tf b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/variables.tf
similarity index 89%
rename from enterprise_scale/construction_sets/aks/variables.tf
rename to enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/variables.tf
index 75b629f2..d4bf8f3a 100644
--- a/enterprise_scale/construction_sets/aks/variables.tf
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/standalone/variables.tf
@@ -20,7 +20,9 @@ variable "vnets" {
}
variable "tags" {
- default = {}
+ description = "Tags to be used for this resource deployment."
+ type = map(any)
+ default = {}
}
variable "aks_clusters" {
@@ -138,3 +140,14 @@ variable "vnet_peerings" {
variable "ip_groups" {
default = {}
}
+
+variable "override_prefix" {
+ default = ""
+}
+variable "flux_settings" {
+ default = {}
+}
+
+variable "aks_cluster_key" {
+ default = null
+}
\ No newline at end of file
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/test/README.md b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/test/README.md
new file mode 100644
index 00000000..f90ce65f
--- /dev/null
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/test/README.md
@@ -0,0 +1,11 @@
+# Integration testing of Enterprise-Scale AKS Construction Set with Terratest
+
+There is a set of sample integration tests that cover some parts of this constructions set. These tests are used by IaC pipeline after deploying each part.
+
+In order to run tests locally you must have [GoLang installed](https://golang.org/doc/install) as Terratest is based on GoLang.
+
+Each test for each part reads expected values from ExpectedValues.yaml file in a corresponding test folder.
+
+[Landing zone test](../landingzone/docs/aks.md#test)
+
+[Standalone test](../standalone/docs/aks.md#test)
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/test/aks/ExpectedValues.yml b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/test/aks/ExpectedValues.yml
new file mode 100644
index 00000000..02d74586
--- /dev/null
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/test/aks/ExpectedValues.yml
@@ -0,0 +1,13 @@
+ClusterName: "aks-akscluster-re1-001"
+ResourceGroupName: "rg-aks-re1"
+DefaultNodePoolName: "sharedsvc"
+UserNodepoolName: "npuser01"
+AgentCount: 3
+OMSAgentEnabled: true
+AzurePolicyEnabled: true
+NetworkPlugin: "azure"
+ManagedOutboundIpCount: 1
+RBACEnabled: true
+NetworkPolicy: ""
+KeyVaultName: "kv-secrets"
+
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/test/aks/aks_test.go b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/test/aks/aks_test.go
new file mode 100644
index 00000000..4b6168f6
--- /dev/null
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/test/aks/aks_test.go
@@ -0,0 +1,139 @@
+package aks
+
+import (
+ "secureaks/tests/util"
+ "testing"
+
+ "github.com/Azure/azure-sdk-for-go/services/containerservice/mgmt/2019-11-01/containerservice"
+ "github.com/gruntwork-io/terratest/modules/azure"
+ "github.com/stretchr/testify/assert"
+ "github.com/stretchr/testify/require"
+)
+
+type ExpectedValues struct {
+ ClusterName string
+ ResourceGroupName string
+ DefaultNodePoolName string
+ UserNodepoolName string
+ AgentCount int
+ OMSAgentEnabled bool
+ AzurePolicyEnabled bool
+ NetworkPlugin string
+ ManagedOutboundIpCount int
+ RBACEnabled bool
+ NetworkPolicy string
+ KeyVaultName string
+}
+
+func TestAksAgentPoolProfile(t *testing.T) {
+ t.Parallel()
+
+ expectedValues := getExpectedValues()
+
+ cluster := getCluster(t, expectedValues.ResourceGroupName, expectedValues.ClusterName)
+
+ // Test that the Nodepool name matches the Terraform specification
+ assert.Equal(t, expectedValues.DefaultNodePoolName, string(*(*cluster.ManagedClusterProperties.AgentPoolProfiles)[1].Name), "Default node pool didn't not match")
+ assert.Equal(t, expectedValues.UserNodepoolName, string(*(*cluster.ManagedClusterProperties.AgentPoolProfiles)[0].Name), "User node pool didn't match")
+
+ // Test that the Node count matches the Terraform specification
+ assert.Equal(t, expectedValues.AgentCount, int(*(*cluster.ManagedClusterProperties.AgentPoolProfiles)[0].Count))
+ assert.Equal(t, expectedValues.AgentCount, int(*(*cluster.ManagedClusterProperties.AgentPoolProfiles)[1].Count))
+}
+
+func TestAksAddOnProfile(t *testing.T) {
+ t.Parallel()
+
+ expectedValues := getExpectedValues()
+
+ cluster := getCluster(t, expectedValues.ResourceGroupName, expectedValues.ClusterName)
+
+ // Test if OMS agent is enabled
+ assert.Equal(t, expectedValues.OMSAgentEnabled, *(cluster.ManagedClusterProperties.AddonProfiles["omsagent"].Enabled))
+
+ // Test if Azure policy is enabled
+ assert.Equal(t, expectedValues.AzurePolicyEnabled, *(cluster.ManagedClusterProperties.AddonProfiles["azurepolicy"].Enabled))
+}
+
+func TestAksLoadBalancerProfile(t *testing.T) {
+ t.Parallel()
+
+ expectedValues := getExpectedValues()
+
+ cluster := getCluster(t, expectedValues.ResourceGroupName, expectedValues.ClusterName)
+
+ // Test Network type (plugin)
+ assert.Equal(t, expectedValues.NetworkPlugin, string(cluster.NetworkProfile.NetworkPlugin))
+
+ // Test Network policy
+ // assert.Equal(t, expectedValues.NetworkPolicy, string(cluster.NetworkProfile.NetworkPolicy))
+}
+
+func TestAksNetworkProfile(t *testing.T) {
+ t.Parallel()
+
+ //Looks like there is a new bug in AKS API
+ //It returns empty NetworkProfile.LoadBalancerProfile
+ //commenting it out for now
+
+ // expectedValues := getExpectedValues()
+
+ // cluster := getCluster(t, expectedValues.ResourceGroupName, expectedValues.ClusterName)
+ // managedOutboundIpCount := 0
+
+ // Test loadbalancer managed outbound IP count
+ // if cluster.ManagedClusterProperties.NetworkProfile.LoadBalancerProfile != nil {
+ // managedOutboundIpCount = int(*(*&cluster.ManagedClusterProperties.NetworkProfile.LoadBalancerProfile.ManagedOutboundIPs.Count))
+ // }
+
+ //assert.Equal(t, expectedValues.ManagedOutboundIpCount, managedOutboundIpCount)
+}
+
+func TestAksRbacEnbaled(t *testing.T) {
+ t.Parallel()
+
+ expectedValues := getExpectedValues()
+
+ cluster := getCluster(t, expectedValues.ResourceGroupName, expectedValues.ClusterName)
+
+ // Test cluster is RBAC enabled
+ assert.Equal(t, expectedValues.RBACEnabled, *(cluster.ManagedClusterProperties.EnableRBAC))
+
+}
+
+func TestAKSManagedAad(t *testing.T) {
+ t.Parallel()
+ expectedValues := getExpectedValues()
+
+ cluster := getCluster(t, expectedValues.ResourceGroupName, expectedValues.ClusterName)
+
+ // Test AKS-managed Azure Active Directory is enabled
+ assert.NotEmpty(t, *(cluster.ManagedClusterProperties.AadProfile))
+
+}
+
+func getCluster(t *testing.T, expectedResourceGroupName, expectedClusterName string) *containerservice.ManagedCluster {
+ cluster, err := azure.GetManagedClusterE(t, util.ResolveNameWithPrefix(expectedResourceGroupName), util.ResolveNameWithPrefix(expectedClusterName), "")
+ require.NoError(t, err)
+
+ return cluster
+}
+
+func TestKeyVault(t *testing.T) {
+ t.Parallel()
+
+ expectedValues := getExpectedValues()
+
+ keyVaultName := util.ResolveNameWithPrefix(expectedValues.KeyVaultName)
+ resourceGroupName := util.ResolveNameWithPrefix(expectedValues.ResourceGroupName)
+
+ // Test key vault exists
+ keyVault := azure.GetKeyVault(t, resourceGroupName, keyVaultName, "")
+ assert.Equal(t, keyVaultName, *keyVault.Name)
+}
+
+func getExpectedValues() ExpectedValues {
+ var expectedValues ExpectedValues
+ util.ReadTestConfig("ExpectedValues", &expectedValues)
+ return expectedValues
+}
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/test/flux/ExpectedValues.yml b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/test/flux/ExpectedValues.yml
new file mode 100644
index 00000000..b4392681
--- /dev/null
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/test/flux/ExpectedValues.yml
@@ -0,0 +1,2 @@
+K8sContextName: "aks-akscluster-re1-001-admin"
+ClusterBaselineNamespace: "cluster-baseline-settings"
\ No newline at end of file
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/test/flux/flux_test.go b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/test/flux/flux_test.go
new file mode 100644
index 00000000..b7a50b6a
--- /dev/null
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/test/flux/flux_test.go
@@ -0,0 +1,90 @@
+package flux
+
+import (
+ "fmt"
+ "os"
+ "secureaks/tests/util"
+ "testing"
+ "time"
+
+ "github.com/gruntwork-io/terratest/modules/k8s"
+ "github.com/stretchr/testify/require"
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
+)
+
+type ExpectedValues struct {
+ K8sContextName string
+ ClusterBaselineNamespace string
+}
+
+func TestCSIProvider(t *testing.T) {
+ t.Parallel()
+
+ expectedValues := getExpectedValues()
+
+ options := getKubectlOptions(expectedValues.K8sContextName, expectedValues.ClusterBaselineNamespace)
+
+ // Test CSI provider pods
+ csiDriverPods := k8s.ListPods(t, options, metav1.ListOptions{LabelSelector: "app=csi-secrets-store"})
+ for key := range csiDriverPods {
+ err := k8s.WaitUntilPodAvailableE(t, options, csiDriverPods[key].Name, 60, 1*time.Second)
+ require.NoError(t, err)
+ }
+
+ // Test Azure Key Vault CSI provider pods
+ csiAzKeyVaultProviderPods := k8s.ListPods(t, options, metav1.ListOptions{LabelSelector: "app=csi-secrets-store-provider-azure"})
+ for key := range csiAzKeyVaultProviderPods {
+ err := k8s.WaitUntilPodAvailableE(t, options, csiAzKeyVaultProviderPods[key].Name, 60, 1*time.Second)
+ require.NoError(t, err)
+
+ }
+}
+
+func TestFlux(t *testing.T) {
+ t.Parallel()
+ expectedValues := getExpectedValues()
+
+ options := getKubectlOptions(expectedValues.K8sContextName, expectedValues.ClusterBaselineNamespace)
+ fluxpods := k8s.ListPods(t, options, metav1.ListOptions{LabelSelector: "app.kubernetes.io/name=flux"})
+ for key := range fluxpods {
+ err := k8s.WaitUntilPodAvailableE(t, options, fluxpods[key].Name, 60, 1*time.Second)
+ require.NoError(t, err)
+
+ }
+}
+
+func TestAadPodIdentityControllers(t *testing.T) {
+ t.Parallel()
+ expectedValues := getExpectedValues()
+
+ options := getKubectlOptions(expectedValues.K8sContextName, expectedValues.ClusterBaselineNamespace)
+ aadpods := k8s.ListPods(t, options, metav1.ListOptions{LabelSelector: "app.kubernetes.io/name=aad-pod-identity"})
+ for key := range aadpods {
+ err := k8s.WaitUntilPodAvailableE(t, options, aadpods[key].Name, 60, 1*time.Second)
+ require.NoError(t, err)
+ }
+}
+
+func TestKuredControllers(t *testing.T) {
+ t.Parallel()
+ expectedValues := getExpectedValues()
+
+ options := getKubectlOptions(expectedValues.K8sContextName, expectedValues.ClusterBaselineNamespace)
+ kuredpods := k8s.ListPods(t, options, metav1.ListOptions{LabelSelector: "name=kured"})
+ for key := range kuredpods {
+ err := k8s.WaitUntilPodAvailableE(t, options, kuredpods[key].Name, 60, 1*time.Second)
+ require.NoError(t, err)
+
+ }
+}
+
+func getKubectlOptions(contextName, namespace string) *k8s.KubectlOptions {
+ return k8s.NewKubectlOptions(util.ResolveNameWithPrefix(contextName), os.Getenv("KUBECONFIGPATH"), namespace)
+}
+
+func getExpectedValues() ExpectedValues {
+ var expectedValues ExpectedValues
+ util.ReadTestConfig("ExpectedValues", &expectedValues)
+ fmt.Printf("context %s", expectedValues.K8sContextName)
+ return expectedValues
+}
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/test/go.mod b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/test/go.mod
new file mode 100644
index 00000000..65fd76ea
--- /dev/null
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/test/go.mod
@@ -0,0 +1,11 @@
+module secureaks/tests
+
+go 1.15
+
+require (
+ github.com/Azure/azure-sdk-for-go v46.0.0+incompatible
+ github.com/gruntwork-io/terratest v0.32.18
+ github.com/spf13/viper v1.3.2
+ github.com/stretchr/testify v1.7.0
+ k8s.io/apimachinery v0.19.3
+)
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/test/go.sum b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/test/go.sum
new file mode 100644
index 00000000..d17db843
--- /dev/null
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/test/go.sum
@@ -0,0 +1,674 @@
+cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
+cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
+cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
+cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
+cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
+cloud.google.com/go v0.51.0 h1:PvKAVQWCtlGUSlZkGW3QLelKaWq7KYv/MW1EboG8bfM=
+cloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw=
+cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
+cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
+cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
+cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
+dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
+github.com/Azure/azure-sdk-for-go v35.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
+github.com/Azure/azure-sdk-for-go v38.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
+github.com/Azure/azure-sdk-for-go v46.0.0+incompatible h1:4qlEOCDcDQZTGczYGzbGYCdJfVpZLIs8AEo5+MoXBPw=
+github.com/Azure/azure-sdk-for-go v46.0.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
+github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
+github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs=
+github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
+github.com/Azure/go-autorest/autorest v0.9.0/go.mod h1:xyHB1BMZT0cuDHU7I0+g046+BFDTQ8rEZB0s4Yfa6bI=
+github.com/Azure/go-autorest/autorest v0.9.3/go.mod h1:GsRuLYvwzLjjjRoWEIyMUaYq8GNUx2nRB378IPt/1p0=
+github.com/Azure/go-autorest/autorest v0.9.6/go.mod h1:/FALq9T/kS7b5J5qsQ+RSTUdAmGFqi0vUdVNNx8q630=
+github.com/Azure/go-autorest/autorest v0.11.0/go.mod h1:JFgpikqFJ/MleTTxwepExTKnFUKKszPS8UavbQYUMuw=
+github.com/Azure/go-autorest/autorest v0.11.5 h1:glWqPEB2W/zf3bk5BNXG7RL0qD12riPdCk71yJoejD8=
+github.com/Azure/go-autorest/autorest v0.11.5/go.mod h1:foo3aIXRQ90zFve3r0QiDsrjGDUwWhKl0ZOQy1CT14k=
+github.com/Azure/go-autorest/autorest/adal v0.5.0/go.mod h1:8Z9fGy2MpX0PvDjB1pEgQTmVqjGhiHBW7RJJEciWzS0=
+github.com/Azure/go-autorest/autorest/adal v0.8.0/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc=
+github.com/Azure/go-autorest/autorest/adal v0.8.1/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q=
+github.com/Azure/go-autorest/autorest/adal v0.8.2/go.mod h1:ZjhuQClTqx435SRJ2iMlOxPYt3d2C/T/7TiQCVZSn3Q=
+github.com/Azure/go-autorest/autorest/adal v0.9.0/go.mod h1:/c022QCutn2P7uY+/oQWWNcK9YU+MH96NgK+jErpbcg=
+github.com/Azure/go-autorest/autorest/adal v0.9.2 h1:Aze/GQeAN1RRbGmnUJvUj+tFGBzFdIg3293/A9rbxC4=
+github.com/Azure/go-autorest/autorest/adal v0.9.2/go.mod h1:/3SMAM86bP6wC9Ev35peQDUeqFZBMH07vvUOmg4z/fE=
+github.com/Azure/go-autorest/autorest/azure/auth v0.5.1 h1:bvUhZciHydpBxBmCheUgxxbSwJy7xcfjkUsjUcqSojc=
+github.com/Azure/go-autorest/autorest/azure/auth v0.5.1/go.mod h1:ea90/jvmnAwDrSooLH4sRIehEPtG/EPUXavDh31MnA4=
+github.com/Azure/go-autorest/autorest/azure/cli v0.4.0 h1:Ml+UCrnlKD+cJmSzrZ/RDcDw86NjkRUpnFh7V5JUhzU=
+github.com/Azure/go-autorest/autorest/azure/cli v0.4.0/go.mod h1:JljT387FplPzBA31vUcvsetLKF3pec5bdAxjVU4kI2s=
+github.com/Azure/go-autorest/autorest/date v0.1.0/go.mod h1:plvfp3oPSKwf2DNjlBjWF/7vwR+cUD/ELuzDCXwHUVA=
+github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g=
+github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw=
+github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74=
+github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
+github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0=
+github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM=
+github.com/Azure/go-autorest/autorest/mocks v0.4.0/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k=
+github.com/Azure/go-autorest/autorest/mocks v0.4.1 h1:K0laFcLE6VLTOwNgSxaGbUcLPuGXlNkbVvq4cW4nIHk=
+github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k=
+github.com/Azure/go-autorest/autorest/to v0.2.0/go.mod h1:GunWKJp1AEqgMaGLV+iocmRAJWqST1wQYhyyjXJ3SJc=
+github.com/Azure/go-autorest/autorest/to v0.3.0 h1:zebkZaadz7+wIQYgC7GXaz3Wb28yKYfVkkBKwc38VF8=
+github.com/Azure/go-autorest/autorest/to v0.3.0/go.mod h1:MgwOyqaIuKdG4TL/2ywSsIWKAfJfgHDo8ObuUk3t5sA=
+github.com/Azure/go-autorest/autorest/validation v0.1.0/go.mod h1:Ha3z/SqBeaalWQvokg3NZAlQTalVMtOIAs1aGK7G6u8=
+github.com/Azure/go-autorest/autorest/validation v0.3.0 h1:3I9AAI63HfcLtphd9g39ruUwRI+Ca+z/f36KHPFRUss=
+github.com/Azure/go-autorest/autorest/validation v0.3.0/go.mod h1:yhLgjC0Wda5DYXl6JAsWyUe4KVNffhoDhG0zVzUMo3E=
+github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc=
+github.com/Azure/go-autorest/logger v0.2.0 h1:e4RVHVZKC5p6UANLJHkM4OfR1UKZPj8Wt8Pcx+3oqrE=
+github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8=
+github.com/Azure/go-autorest/tracing v0.5.0/go.mod h1:r/s2XiOKccPW3HrqB+W0TQzfbtp2fGCgRFtBroKn4Dk=
+github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo=
+github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
+github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
+github.com/GoogleCloudPlatform/k8s-cloud-provider v0.0.0-20190822182118-27a4ced34534/go.mod h1:iroGtC8B3tQiqtds1l+mgk/BBOrxbqjH+eUfFQYRc14=
+github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
+github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
+github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
+github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
+github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
+github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
+github.com/agext/levenshtein v1.2.1/go.mod h1:JEDfjyjHDjOF/1e4FlBE/PkbqA9OfWu2ki2W0IB5558=
+github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
+github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
+github.com/apparentlymart/go-dump v0.0.0-20180507223929-23540a00eaa3/go.mod h1:oL81AME2rN47vu18xqj1S1jPIPuN7afo62yKTNn3XMM=
+github.com/apparentlymart/go-textseg v1.0.0/go.mod h1:z96Txxhf3xSFMPmb5X/1W05FF/Nj9VFpLOpjS5yuumk=
+github.com/apparentlymart/go-textseg/v12 v12.0.0/go.mod h1:S/4uRK2UtaQttw1GenVJEynmyUenKwP++x/+DdGV/Ec=
+github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
+github.com/aws/aws-lambda-go v1.13.3/go.mod h1:4UKl9IzQMoD+QF79YdCuzCwp8VbmG4VAQwij/eHl5CU=
+github.com/aws/aws-sdk-go v1.16.26/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
+github.com/aws/aws-sdk-go v1.27.1 h1:MXnqY6SlWySaZAqNnXThOvjRFdiiOuKtC6i7baFdNdU=
+github.com/aws/aws-sdk-go v1.27.1/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
+github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
+github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
+github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
+github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
+github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc h1:biVzkmvwrH8WK8raXaxBx6fRVTlJILwEwQGL1I/ByEI=
+github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8=
+github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
+github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
+github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
+github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
+github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8=
+github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
+github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
+github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
+github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc=
+github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
+github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
+github.com/coreos/go-systemd v0.0.0-20180511133405-39ca1b05acc7/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
+github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
+github.com/coreos/pkg v0.0.0-20160727233714-3ac0863d7acf/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
+github.com/coreos/pkg v0.0.0-20180108230652-97fdf19511ea/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
+github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk=
+github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
+github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
+github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM=
+github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
+github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
+github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
+github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
+github.com/dimchansky/utfbom v1.1.0 h1:FcM3g+nofKgUteL8dm/UpdRXNC9KmADgTpLKsu0TRo4=
+github.com/dimchansky/utfbom v1.1.0/go.mod h1:rO41eb7gLfo8SF1jd9F8HplJm1Fewwi4mQvIirEdv+8=
+github.com/dnaeon/go-vcr v1.0.1/go.mod h1:aBB1+wY4s93YsC3HHjMBMrwTj2R9FHDzUr9KyGc8n1E=
+github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
+github.com/docker/cli v0.0.0-20200109221225-a4f60165b7a3/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
+github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
+github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
+github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
+github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y=
+github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
+github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
+github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
+github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c h1:ZfSZ3P3BedhKGUhzj7BQlPSU4OvT6tfOKe3DVHzOA7s=
+github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
+github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
+github.com/dustin/go-humanize v0.0.0-20171111073723-bb3d318650d4/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
+github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
+github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
+github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
+github.com/elazarl/goproxy v0.0.0-20190911111923-ecfe977594f1 h1:yY9rWGoXv1U5pl4gxqlULARMQD7x0QG85lqEXTWysik=
+github.com/elazarl/goproxy v0.0.0-20190911111923-ecfe977594f1/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM=
+github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2 h1:dWB6v3RcOy03t/bUadywsbyrQwCqZeNIEX6M1OtSZOM=
+github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8=
+github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
+github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
+github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
+github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
+github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
+github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
+github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
+github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
+github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
+github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
+github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
+github.com/go-errors/errors v1.0.2-0.20180813162953-d98b870cc4e0 h1:skJKxRtNmevLqnayafdLe2AsenqRupVmzZSqrvb5caU=
+github.com/go-errors/errors v1.0.2-0.20180813162953-d98b870cc4e0/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
+github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
+github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
+github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
+github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
+github.com/go-logr/logr v0.2.0 h1:QvGt2nLcHH0WK9orKa+ppBPAxREcH364nPUedEpK0TY=
+github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
+github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0=
+github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg=
+github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
+github.com/go-openapi/jsonreference v0.0.0-20160704190145-13c6e3589ad9/go.mod h1:W3Z9FmVs9qj+KR4zFKmDPGiLdk1D9Rlm7cyMvf57TTg=
+github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc=
+github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8=
+github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc=
+github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
+github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I=
+github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
+github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
+github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA=
+github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
+github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
+github.com/go-test/deep v1.0.3/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA=
+github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
+github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
+github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
+github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=
+github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
+github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
+github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
+github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
+github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
+github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
+github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
+github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
+github.com/golang/protobuf v1.4.2 h1:+Z5KGCizgyZCbGh1KZqA0fcLLkwbsjIzS4aV2v7wJX0=
+github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
+github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
+github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4=
+github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-containerregistry v0.0.0-20200110202235-f4fb41bf00a3/go.mod h1:2wIuQute9+hhWqvL3vEI7YB0EKluF4WcPzI1eAliazk=
+github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
+github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g=
+github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
+github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
+github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
+github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
+github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
+github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
+github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
+github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
+github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
+github.com/googleapis/gnostic v0.0.0-20170729233727-0c5108395e2d/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
+github.com/googleapis/gnostic v0.2.2/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
+github.com/googleapis/gnostic v0.4.1 h1:DLJCy1n/vrD4HPjOvYcT8aYQXpPIzoRZONaYwyycI+I=
+github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg=
+github.com/gophercloud/gophercloud v0.1.0/go.mod h1:vxM41WHh5uqHVBMZHzuwNOHh8XEoIEcSTewFxm1c5g8=
+github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
+github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
+github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
+github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
+github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
+github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
+github.com/grpc-ecosystem/grpc-gateway v1.9.5/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
+github.com/gruntwork-io/go-commons v0.8.0 h1:k/yypwrPqSeYHevLlEDmvmgQzcyTwrlZGRaxEM6G0ro=
+github.com/gruntwork-io/go-commons v0.8.0/go.mod h1:gtp0yTtIBExIZp7vyIV9I0XQkVwiQZze678hvDXof78=
+github.com/gruntwork-io/terratest v0.32.18 h1:nkke44G0vvylCq6u8hAJAVuS1cq87wPg9979CsiTYtg=
+github.com/gruntwork-io/terratest v0.32.18/go.mod h1:9YwOlGbCEOBRL8cvTdfEiTDWcj/f81j/o8FBYpOgdS4=
+github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
+github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
+github.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI=
+github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=
+github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
+github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
+github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
+github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
+github.com/hashicorp/hcl/v2 v2.8.2/go.mod h1:bQTN5mpo+jewjJgh8jr0JUguIi7qPHUF6yIfAEN3jqY=
+github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
+github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
+github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
+github.com/imdario/mergo v0.3.7 h1:Y+UAYTZ7gDEuOfhxKWy+dvb5dRQ6rJjFSdX2HZY1/gI=
+github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
+github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
+github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a/go.mod h1:yL958EeXv8Ylng6IfnvG4oflryUi3vgA3xPs9hmII1s=
+github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=
+github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
+github.com/joefitzgerald/rainbow-reporter v0.1.0/go.mod h1:481CNgqmVHQZzdIbN52CupLJyoVwB10FQ/IQlF1pdL8=
+github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
+github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
+github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
+github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/json-iterator/go v1.1.8/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68=
+github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
+github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
+github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
+github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
+github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
+github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
+github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
+github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
+github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
+github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
+github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
+github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
+github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k=
+github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY=
+github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
+github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
+github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
+github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
+github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
+github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
+github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
+github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
+github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
+github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
+github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
+github.com/mattn/go-zglob v0.0.1/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo=
+github.com/mattn/go-zglob v0.0.2-0.20190814121620-e3c945676326/go.mod h1:9fxibJccNxU2cnpIKLRRFA7zX7qhkJIQWBb449FYHOo=
+github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
+github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY=
+github.com/miekg/dns v1.1.31/go.mod h1:KNUDUusw/aVsxyTYZM1oqvCicbwhgbNgztCETuNZ7xM=
+github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
+github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
+github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
+github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
+github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v0.0.0-20180320133207-05fbef0ca5da/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
+github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
+github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
+github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
+github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
+github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
+github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
+github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
+github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
+github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
+github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
+github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
+github.com/oracle/oci-go-sdk v7.1.0+incompatible/go.mod h1:VQb79nF8Z2cwLkLS35ukwStZIg5F66tcBccjip/j888=
+github.com/pelletier/go-toml v1.2.0 h1:T5zMGML61Wp+FlcbWjRDT7yAxhJNAiPPLOFECq181zc=
+github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
+github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
+github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA=
+github.com/pquerna/otp v1.2.0 h1:/A3+Jn+cagqayeR3iHs/L62m5ue7710D35zl1zJ1kok=
+github.com/pquerna/otp v1.2.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg=
+github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
+github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
+github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo=
+github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
+github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
+github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
+github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
+github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M=
+github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
+github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc=
+github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
+github.com/rubiojr/go-vhd v0.0.0-20160810183302-0bfd3b39853c/go.mod h1:DM5xW0nvfNNm2uytzsvhI3OnX8uzaRAg8UX/CnDqbto=
+github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
+github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
+github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
+github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
+github.com/satori/go.uuid v1.2.0 h1:0uYX9dsZ2yD7q2RtLRtPSdGDWzjeM3TbMJP9utgA0ww=
+github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
+github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U=
+github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
+github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
+github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
+github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
+github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
+github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
+github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
+github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
+github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc=
+github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
+github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8=
+github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
+github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
+github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
+github.com/spf13/jwalterweatherman v1.0.0 h1:XHEdyB+EcvlqZamSM4ZOMGlc93t6AcsBEu9Gc1vn7yk=
+github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
+github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/spf13/pflag v1.0.1/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/spf13/pflag v1.0.2/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
+github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+github.com/spf13/viper v1.3.2 h1:VUFqw5KcqRf7i70GOzW7N+Q7+gxVBkSSqiXB12+JQ4M=
+github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
+github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
+github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
+github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
+github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
+github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
+github.com/urfave/cli v1.22.2 h1:gsqYFH8bb9ekPA12kRo0hfjngWQjkJPlN9R0N78BoUo=
+github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
+github.com/vdemeester/k8s-pkg-credentialprovider v0.0.0-20200107171650-7c61ffa44238/go.mod h1:JwQJCMWpUDqjZrB5jpw0f5VbN7U95zxFy1ZDpoEarGo=
+github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk=
+github.com/vmware/govmomi v0.20.3/go.mod h1:URlwyTFZX72RmxtxuaFL2Uj3fD1JTvZdx59bHWk6aFU=
+github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
+github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
+github.com/zclconf/go-cty v1.2.0/go.mod h1:hOPWgoHbaTUnI5k4D2ld+GRpFJSCe6bCM7m1q/N4PQ8=
+go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
+go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg=
+go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
+go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
+go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
+go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
+go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
+go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
+golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20190211182817-74369b46fc67/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/exp v0.0.0-20190312203227-4b39c73a6495/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
+golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
+golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
+golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
+golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
+golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
+golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
+golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
+golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
+golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
+golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
+golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
+golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
+golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180811021610-c39426892332/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
+golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU=
+golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw=
+golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190502175342-a43fa875dd82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4 h1:5/PjkGUjvEU5Gl6BxmvKRPpqo2uNMv4rcHBMwzk/st8=
+golang.org/x/sys v0.0.0-20200622214017-ed371f2e16b4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
+golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
+golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs=
+golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
+golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20190706070813-72ffa07ba3db/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI=
+golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191205215504-7b8c8591a921/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191216052735-49a3e744a425/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/tools v0.0.0-20200113040837-eac381796e91/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
+golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+gonum.org/v1/gonum v0.0.0-20190331200053-3d26580ed485/go.mod h1:2ltnJ7xHfj0zHS40VVPYEAAMTa3ZGguvHGBSJeRWqE0=
+gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw=
+gonum.org/v1/netlib v0.0.0-20190331212654-76723241ea4e/go.mod h1:kS+toOQn6AQKjmKJ7gzohV1XkqsFehRA2FbsbkopSuQ=
+google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
+google.golang.org/api v0.6.1-0.20190607001116-5213b8090861/go.mod h1:btoxGiFvQNVUZQ8W08zLtrVS08CNpINPEfxXxgJL1Q4=
+google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
+google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
+google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
+google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
+google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
+google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
+google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM=
+google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
+google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
+google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
+google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
+google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
+google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
+google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
+google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
+google.golang.org/grpc v1.23.1/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
+google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA=
+google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
+google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
+google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
+google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
+google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
+google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
+google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
+google.golang.org/protobuf v1.24.0 h1:UhZDfRO8JRQru4/+LlLE0BRKGF8L+PICnvYZmx/fEGA=
+google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
+gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
+gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
+gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
+gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
+gopkg.in/gcfg.v1 v1.2.0/go.mod h1:yesOnuUOFQAhST5vPY4nbZsb/huCgGGXlipJsBn0b3o=
+gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
+gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
+gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
+gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
+gopkg.in/square/go-jose.v2 v2.2.2/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
+gopkg.in/warnings.v0 v0.1.1/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
+gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
+gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
+gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
+honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
+k8s.io/api v0.17.0/go.mod h1:npsyOePkeP0CPwyGfXDHxvypiYMJxBWAMpQxCaJ4ZxI=
+k8s.io/api v0.19.3 h1:GN6ntFnv44Vptj/b+OnMW7FmzkpDoIDLZRvKX3XH9aU=
+k8s.io/api v0.19.3/go.mod h1:VF+5FT1B74Pw3KxMdKyinLo+zynBaMBiAfGMuldcNDs=
+k8s.io/apimachinery v0.17.0/go.mod h1:b9qmWdKlLuU9EBh+06BtLcSf/Mu89rWL33naRxs1uZg=
+k8s.io/apimachinery v0.19.3 h1:bpIQXlKjB4cB/oNpnNnV+BybGPR7iP5oYpsOTEJ4hgc=
+k8s.io/apimachinery v0.19.3/go.mod h1:DnPGDnARWFvYa3pMHgSxtbZb7gpzzAZ1pTfaUNDVlmA=
+k8s.io/apiserver v0.17.0/go.mod h1:ABM+9x/prjINN6iiffRVNCBR2Wk7uY4z+EtEGZD48cg=
+k8s.io/client-go v0.17.0/go.mod h1:TYgR6EUHs6k45hb6KWjVD6jFZvJV4gHDikv/It0xz+k=
+k8s.io/client-go v0.19.3 h1:ctqR1nQ52NUs6LpI0w+a5U+xjYwflFwA13OJKcicMxg=
+k8s.io/client-go v0.19.3/go.mod h1:+eEMktZM+MG0KO+PTkci8xnbCZHvj9TqR6Q1XDUIJOM=
+k8s.io/cloud-provider v0.17.0/go.mod h1:Ze4c3w2C0bRsjkBUoHpFi+qWe3ob1wI2/7cUn+YQIDE=
+k8s.io/code-generator v0.0.0-20191121015212-c4c8f8345c7e/go.mod h1:DVmfPQgxQENqDIzVR2ddLXMH34qeszkKSdH/N+s+38s=
+k8s.io/component-base v0.17.0/go.mod h1:rKuRAokNMY2nn2A6LP/MiwpoaMRHpfRnrPaUJJj1Yoc=
+k8s.io/csi-translation-lib v0.17.0/go.mod h1:HEF7MEz7pOLJCnxabi45IPkhSsE/KmxPQksuCrHKWls=
+k8s.io/gengo v0.0.0-20190128074634-0689ccc1d7d6/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
+k8s.io/gengo v0.0.0-20190822140433-26a664648505/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
+k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
+k8s.io/klog v0.0.0-20181102134211-b9b56d5dfc92/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
+k8s.io/klog v0.3.0/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
+k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8=
+k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
+k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
+k8s.io/klog/v2 v2.2.0 h1:XRvcwJozkgZ1UQJmfMGpvRthQHOvihEhYtDfAaxMz/A=
+k8s.io/klog/v2 v2.2.0/go.mod h1:Od+F08eJP+W3HUb4pSrPpgp9DGU4GzlpG/TmITuYh/Y=
+k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E=
+k8s.io/kube-openapi v0.0.0-20200805222855-6aeccd4b50c6/go.mod h1:UuqjUnNftUyPE5H64/qeyjQoUZhGpeFDVdxjTeEVN2o=
+k8s.io/legacy-cloud-providers v0.17.0/go.mod h1:DdzaepJ3RtRy+e5YhNtrCYwlgyK87j/5+Yfp0L9Syp8=
+k8s.io/utils v0.0.0-20191114184206-e782cd3c129f/go.mod h1:sZAwmy6armz5eXlNoLmJcl4F1QuKu7sr+mFQ0byX7Ew=
+k8s.io/utils v0.0.0-20200729134348-d5654de09c73 h1:uJmqzgNWG7XyClnU/mLPBWwfKKF1K8Hf8whTseBgJcg=
+k8s.io/utils v0.0.0-20200729134348-d5654de09c73/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
+modernc.org/cc v1.0.0/go.mod h1:1Sk4//wdnYJiUIxnW8ddKpaOJCF37yAdqYnkxUpaYxw=
+modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk=
+modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k=
+modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs=
+modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I=
+rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
+sigs.k8s.io/structured-merge-diff v0.0.0-20190525122527-15d366b2352e/go.mod h1:wWxsB5ozmmv/SG7nM11ayaAW51xMvak/t1r0CSlcokI=
+sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06 h1:zD2IemQ4LmOcAumeiyDWXKUI2SO0NYDe3H6QGvPOVgU=
+sigs.k8s.io/structured-merge-diff v1.0.1-0.20191108220359-b1b620dd3f06/go.mod h1:/ULNhyfzRopfcjskuui0cTITekDduZ7ycKN3oUT9R18=
+sigs.k8s.io/structured-merge-diff/v4 v4.0.1 h1:YXTMot5Qz/X1iBRJhAt+vI+HVttY0WkSqqhKxQ0xVbA=
+sigs.k8s.io/structured-merge-diff/v4 v4.0.1/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
+sigs.k8s.io/yaml v1.1.0/go.mod h1:UJmg0vDUVViEyp3mgSv9WPwZCDxu4rQW1olrI1uml+o=
+sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
+sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/test/launchpad/launchpad_test.go b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/test/launchpad/launchpad_test.go
new file mode 100755
index 00000000..f5a75384
--- /dev/null
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/test/launchpad/launchpad_test.go
@@ -0,0 +1,187 @@
+package launchpad
+
+import (
+ "context"
+ "fmt"
+ "os"
+ "testing"
+
+ "github.com/gruntwork-io/terratest/modules/azure"
+ "github.com/stretchr/testify/assert"
+)
+
+type LandingZone struct {
+ Level int
+ ResourceGroupName string
+ KeyVaultName string
+ StorageAccountName string
+}
+
+type TestStructure struct {
+ Environment string
+ Prefix string
+ SubscriptionID string
+ LandingZones []LandingZone
+}
+
+func prepareTestTable() TestStructure {
+ prefix := os.Getenv("PREFIX")
+
+ test := TestStructure{
+ Prefix: prefix,
+ SubscriptionID: os.Getenv("ARM_SUBSCRIPTION_ID"),
+ Environment: os.Getenv("ENVIRONMENT"),
+ LandingZones: make([]LandingZone, 0),
+ }
+
+ for iLoop := 0; iLoop < 4; iLoop++ {
+ test.LandingZones = append(test.LandingZones, LandingZone{
+ Level: iLoop,
+ ResourceGroupName: fmt.Sprintf("%s-rg-caf-launchpad-level%d", prefix, iLoop),
+ KeyVaultName: fmt.Sprintf("%s-kv-level%d", prefix, iLoop),
+ StorageAccountName: fmt.Sprintf("%sstcafl%d", prefix, iLoop),
+ })
+ }
+
+ return test
+}
+
+func TestLaunchpadResourceGroupIsExists(t *testing.T) {
+ t.Parallel()
+
+ test := prepareTestTable()
+
+ for _, landingZone := range test.LandingZones {
+ exists := azure.ResourceGroupExists(t, landingZone.ResourceGroupName, test.SubscriptionID)
+
+ assert.True(t, exists, fmt.Sprintf("Resource group (%s) does not exist", landingZone.ResourceGroupName))
+ }
+}
+
+func TestLaunchpadResourceGroupIsExistsViaClient(t *testing.T) {
+ t.Parallel()
+
+ test := prepareTestTable()
+
+ client, _ := azure.GetResourceGroupClientE(test.SubscriptionID)
+
+ for _, landingZone := range test.LandingZones {
+ _, err := client.CheckExistence(context.Background(), landingZone.ResourceGroupName)
+
+ assert.NoError(t, err, fmt.Sprintf("Resource group (%s) does not exist", landingZone.ResourceGroupName))
+ }
+}
+
+func TestLaunchpadResourceGroupHasTags(t *testing.T) {
+ t.Parallel()
+
+ test := prepareTestTable()
+
+ client, errClient := azure.GetResourceGroupClientE(test.SubscriptionID)
+
+ assert.NoError(t, errClient, "ResourceGroup Client couldn't read")
+
+ for _, landingZone := range test.LandingZones {
+ rg, errRG := client.Get(context.Background(), landingZone.ResourceGroupName)
+
+ assert.NoError(t, errRG, fmt.Sprintf("ResourceGroup (%s) couldn't read", landingZone.ResourceGroupName))
+
+ assert.Equal(t, test.Environment, *rg.Tags["environment"], "Environment Tag is not correct")
+ assert.Equal(t, "launchpad", *rg.Tags["landingzone"], "LandingZone Tag is not correct")
+ assert.Equal(t, fmt.Sprintf("level%d", landingZone.Level), *rg.Tags["level"], "Level Tag is not correct")
+ }
+}
+
+func TestLaunchpadResourceGroupHasKeyVault(t *testing.T) {
+ t.Parallel()
+
+ test := prepareTestTable()
+
+ for _, landingZone := range test.LandingZones {
+ kv := azure.GetKeyVault(t, landingZone.ResourceGroupName, landingZone.KeyVaultName, test.SubscriptionID)
+
+ assert.NotNil(t, kv, fmt.Sprintf("KeyVault (%s) does not exists", landingZone.KeyVaultName))
+ }
+}
+
+func TestLaunchpadResourceGroupHasStorageAccount(t *testing.T) {
+ t.Parallel()
+
+ test := prepareTestTable()
+
+ for _, landingZone := range test.LandingZones {
+ exists := azure.StorageAccountExists(t, landingZone.StorageAccountName, landingZone.ResourceGroupName, test.SubscriptionID)
+
+ assert.True(t, exists, fmt.Sprintf("Storage Account (%s) does not exists", landingZone.StorageAccountName))
+ }
+}
+
+func TestLaunchpadKeyVaultHasSubscriptionIdSecret(t *testing.T) {
+ t.Parallel()
+
+ test := prepareTestTable()
+
+ for _, landingZone := range test.LandingZones {
+ exists := azure.KeyVaultSecretExists(t, landingZone.KeyVaultName, "subscription-id")
+
+ assert.True(t, exists, "Subscription Id Secret does not exists")
+ }
+}
+
+func TestLaunchpadKeyVaultHasTenantIdSecret(t *testing.T) {
+ t.Parallel()
+
+ test := prepareTestTable()
+
+ for _, landingZone := range test.LandingZones {
+ exists := azure.KeyVaultSecretExists(t, landingZone.KeyVaultName, "tenant-id")
+
+ assert.True(t, exists, "Tenant Id Secret does not exists")
+ }
+}
+
+func TestLaunchpadKeyVaultHasTags(t *testing.T) {
+ t.Parallel()
+
+ test := prepareTestTable()
+
+ for _, landingZone := range test.LandingZones {
+ kv := azure.GetKeyVault(t, landingZone.ResourceGroupName, landingZone.KeyVaultName, test.SubscriptionID)
+
+ assert.Equal(t, test.Environment, *kv.Tags["environment"], "Environment Tag is not correct")
+ assert.Equal(t, "launchpad", *kv.Tags["landingzone"], "LandingZone Tag is not correct")
+ assert.Equal(t, fmt.Sprintf("level%d", landingZone.Level), *kv.Tags["level"], "Level Tag is not correct")
+ assert.Equal(t, fmt.Sprintf("level%d", landingZone.Level), *kv.Tags["tfstate"], "TF State Tag is not correct")
+ }
+}
+
+func TestLaunchpadStorageAccountHasTags(t *testing.T) {
+ t.Parallel()
+
+ test := prepareTestTable()
+
+ for _, landingZone := range test.LandingZones {
+ storage, err := azure.GetStorageAccountE(landingZone.StorageAccountName, landingZone.ResourceGroupName, test.SubscriptionID)
+
+ assert.NoError(t, err, "Storage Account couldn't read")
+
+ assert.Equal(t, test.Environment, *storage.Tags["environment"], "Environment Tag is not correct")
+ assert.Equal(t, "launchpad", *storage.Tags["landingzone"], "LandingZone Tag is not correct")
+ assert.Equal(t, fmt.Sprintf("level%d", landingZone.Level), *storage.Tags["level"], "Level Tag is not correct")
+ assert.Equal(t, fmt.Sprintf("level%d", landingZone.Level), *storage.Tags["tfstate"], "TF State Tag is not correct")
+ }
+}
+
+func TestLaunchpadStorageAccountHasTFStateContainer(t *testing.T) {
+ t.Parallel()
+
+ test := prepareTestTable()
+
+ for _, landingZone := range test.LandingZones {
+ containerName := "tfstate"
+
+ exists := azure.StorageBlobContainerExists(t, containerName, landingZone.StorageAccountName, landingZone.ResourceGroupName, test.SubscriptionID)
+
+ assert.True(t, exists, "TF State Container does not exist")
+ }
+}
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/test/main.go b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/test/main.go
new file mode 100644
index 00000000..2d499135
--- /dev/null
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/test/main.go
@@ -0,0 +1,25 @@
+package main
+
+import (
+ "testing"
+
+ "util"
+)
+
+type Configurations struct {
+ imname string
+ rgname string
+}
+
+func TestManagedIdentity(t *testing.T) {
+ t.Parallel()
+ //TODO: Once Terrtest helper for Azure managed identity is developed, add tests for Azure managed identity.
+
+}
+
+func getTestConfig() Configurations {
+ var configuration Configurations
+ util.ReadTestConfig("config.yaml", configuration)
+ // var test1 = util.Test
+ return configuration
+}
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/test/shared_services/ExpectedValues.yml b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/test/shared_services/ExpectedValues.yml
new file mode 100644
index 00000000..aaf13790
--- /dev/null
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/test/shared_services/ExpectedValues.yml
@@ -0,0 +1,2 @@
+logWorkspaceName: "log-logs"
+logResourceGroupName: "rg-ops_re1"
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/test/shared_services/shared_services_test.go b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/test/shared_services/shared_services_test.go
new file mode 100644
index 00000000..5077c617
--- /dev/null
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/test/shared_services/shared_services_test.go
@@ -0,0 +1,32 @@
+package sharedservices
+
+import (
+ "secureaks/tests/util"
+ "testing"
+
+ "github.com/gruntwork-io/terratest/modules/azure"
+ "github.com/stretchr/testify/assert"
+)
+
+type ExpectedValues struct {
+ LogWorkspaceName string
+ LogResourceGroupName string
+}
+
+func TestLogAnalytics(t *testing.T) {
+ t.Parallel()
+
+ expectedValues := getExpectedValues()
+
+ workSpaceName := util.ResolveNameWithPrefix(expectedValues.LogWorkspaceName)
+ resourceGroupName := util.ResolveNameWithPrefix(expectedValues.LogResourceGroupName)
+
+ workspaceExists := azure.LogAnalyticsWorkspaceExists(t, workSpaceName, resourceGroupName, "")
+ assert.True(t, workspaceExists, "log analytics workspace not found.")
+}
+
+func getExpectedValues() ExpectedValues {
+ var expectedValues ExpectedValues
+ util.ReadTestConfig("ExpectedValues", &expectedValues)
+ return expectedValues
+}
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/test/util/util.go b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/test/util/util.go
new file mode 100644
index 00000000..4e01920b
--- /dev/null
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/test/util/util.go
@@ -0,0 +1,26 @@
+package util
+
+import (
+ "fmt"
+ "os"
+
+ "github.com/spf13/viper"
+)
+
+func ReadTestConfig(configFile string, configuration interface{}) {
+ viper.SetConfigName(configFile)
+ viper.AddConfigPath(".")
+ viper.SetConfigType("yml")
+ if err := viper.ReadInConfig(); err != nil {
+ fmt.Printf("Error reading config file, %s", err)
+ }
+
+ err := viper.Unmarshal(configuration)
+ if err != nil {
+ fmt.Printf("Unable to decode into struct, %v", err)
+ }
+}
+
+func ResolveNameWithPrefix(rawName string) string {
+ return fmt.Sprintf("%s-%s", os.Getenv("PREFIX"), rawName)
+}
diff --git a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/workloads/baseline/traefik.yaml b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/workloads/baseline/traefik.yaml
index 98ae8ff1..4fd321aa 100644
--- a/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/workloads/baseline/traefik.yaml
+++ b/enterprise_scale/construction_sets/aks/online/aks_secure_baseline/workloads/baseline/traefik.yaml
@@ -161,7 +161,7 @@ metadata:
app.kubernetes.io/instance: traefik-ingress-ilb
annotations:
service.beta.kubernetes.io/azure-load-balancer-internal: "true"
- service.beta.kubernetes.io/azure-load-balancer-internal-subnet: erfv-snet-aks_ingress
+ service.beta.kubernetes.io/azure-load-balancer-internal-subnet: epli-snet-aks_ingress
spec:
type: LoadBalancer
loadBalancerIP: 10.100.82.10