From 9a050f1543af7b46383d6a3b0cf33c46130a28c7 Mon Sep 17 00:00:00 2001 From: lolorol Date: Wed, 28 Oct 2020 16:13:56 +0800 Subject: [PATCH] October release (#82) * Add support for TF013 beta 3 * Remove workspace and transition settings to devcontainer * Add --clone-launchpad * Remove --clone-error writing to stdout download progress * Remove launchpad command Remove launchpad landing zone from rover * Cleanup dockerfile * Refactor the command logic for more scalability * Fix a destroy condition * Fix command conditions + cleanup * Fix rover clone * Fix a CI destroy condition * #56 * Add ssh server for Azure aci * Updating port for Azure bastion * Fix sshd port to 22 for aci * Regenerate sshd keys if missing * Make the sshd.sh executable * Run sshd in non-root container * Fix docker in non-root mode * Upgrade tools version Cleanup variables * Remove password for ssh Change ssh server config * Add terraform 0.12.29 * Add 0.13.0-rc1 docker image * Update changelog.md * Update changelog.md * Update rover to version 13 GA * Create .gitattributes * Improvements to support multi layers and sub * Fix plugin-cache creation * Fix plug-in folder creation * Add rover import and state list Add build local image * Fix minor upgrade for azcli and tfdoc * Add Ansible * Adding codespaces support (#72) * Updating tools version * Add ansible * Multi-layer support for 0.4 * Add -var-folder support * Remove constrain to run vscode with logged-in user * Fix execution with msi * Set Tenant_ID when using MSI * fix ARM_TENANT_ID * Add support for Packer * Add yq to parse yaml files * Add rover version verification in vscode * Update devcontainer version * Update yaml to addess Github env variable change * Fix merge in dockerfile * Fix tfsec * Fix a merge issue with ansible * Fix a permission denied in vscode * Set TF_VAR_tenant_id when executed by non user * Fix environment variable for launchpad init * Update rover verify function * Remove version verification in pipelines * Add support for multiple var-folder parameters * Hotfix to prevent duplicates when using var-folder nultiple times * Update docker-compose.yml * Add git pre-commit * Update terraform to 0.13.4 Update AzureCli to 2.14.0 * Update ci * Update vnext trigger Co-authored-by: Arnaud Lheureux Co-authored-by: lolorol --- .devcontainer/devcontainer.json | 26 ++--- .devcontainer/docker-compose.yml | 3 +- .env | 9 +- .github/workflows/ci-branches.yml | 57 ----------- .github/workflows/master.yml | 4 +- .github/workflows/vnext.yml | 14 +-- .pre-commit-config.yaml | 21 ++++ Dockerfile | 102 +++++++++++++------- docker-compose.yml | 1 + scripts/functions.sh | 153 +++++++++++++++++++----------- scripts/rover.sh | 12 ++- 11 files changed, 226 insertions(+), 176 deletions(-) delete mode 100644 .github/workflows/ci-branches.yml create mode 100644 .pre-commit-config.yaml diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index fc4b7429..d8dfd7a8 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,38 +1,38 @@ { "name": "Azure CAF rover", - + // Update the 'dockerComposeFile' list if you have more compose files or use different names. "dockerComposeFile": "docker-compose.yml", - + // Container user to use in VSCode Online and GitHub Codespaces "containerUser" : "vscode", - + // The 'service' property is the name of the service for the container that VS Code should // use. Update this value and .devcontainer/docker-compose.yml to the real service name. "service": "rover", - + // The optional 'workspaceFolder' property is the path VS Code should open by default when // connected. This is typically a volume mount in .devcontainer/docker-compose.yml "workspaceFolder": "/tf/rover", - - // Use 'settings' to set *default* container specific settings.json values on container create. + + // Use 'settings' to set *default* container specific settings.json values on container create. // You can edit these settings after create using File > Preferences > Settings > Remote. - "settings": { + "settings": { "files.eol": "\n", "terminal.integrated.shell.linux": "/bin/bash", "editor.tabSize": 2, - "terminal.integrated.scrollback": 2000, + "terminal.integrated.scrollback": 8000, }, - + // Uncomment the next line if you want start specific services in your Docker Compose config. // "runServices": [], - + // Uncomment this like if you want to keep your containers running after VS Code shuts down. // "shutdownAction": "none", - + // Uncomment the next line to run commands after the container is created. - "postCreateCommand": "cp -R /tmp/.ssh-localhost/* ~/.ssh && chmod 700 ~/.ssh && chmod 600 ~/.ssh/*", - + "postCreateCommand": "cp -R /tmp/.ssh-localhost/* ~/.ssh && sudo chmod 600 ~/.ssh/* && sudo chown -R $(whoami) /tf/caf && git config --global core.editor vi && pre-commit install && pre-commit autoupdate", + // Add the IDs of extensions you want installed when the container is created in the array below. "extensions": [ "4ops.terraform", diff --git a/.devcontainer/docker-compose.yml b/.devcontainer/docker-compose.yml index abd27a86..b2334987 100644 --- a/.devcontainer/docker-compose.yml +++ b/.devcontainer/docker-compose.yml @@ -7,7 +7,8 @@ services: rover: image: aztfmod/roverdev:vnext - + user:vscode + labels: - "caf=Azure CAF" diff --git a/.env b/.env index e368ba4d..a09a29d7 100644 --- a/.env +++ b/.env @@ -1,10 +1,11 @@ -versionTerraform=0.13.3 -versionAzureCli=2.12.1 +versionTerraform=0.13.5 +versionAzureCli=2.14.0 versionKubectl=v1.18.6 versionGit=2.27.0 versionTflint=v0.18.0 versionJq=1.6 -versionDockerCompose=1.25.5 +versionDockerCompose=1.27.3 versionTfsec=v0.27.0 versionTerraformDocs=v0.10.1 -versionAnsible=2.10 \ No newline at end of file +versionAnsible=2.9.13 +versionPacker=1.6.4 diff --git a/.github/workflows/ci-branches.yml b/.github/workflows/ci-branches.yml deleted file mode 100644 index 2cea4a25..00000000 --- a/.github/workflows/ci-branches.yml +++ /dev/null @@ -1,57 +0,0 @@ -name: ci-branches - -on: - push: - branches-ignore: - - master - - vnext - -env: - ARM_CLIENT_SECRET: ${{ secrets.ARM_CLIENT_SECRET }} - ARM_CLIENT_ID: ${{ secrets.ARM_CLIENT_ID }} - ARM_SUBSCRIPTION_ID: ${{ secrets.ARM_SUBSCRIPTION_ID }} - ARM_TENANT_ID: ${{ secrets.ARM_TENANT_ID }} - TF_VAR_azure_devops_pat_token: ${{ secrets.TF_VAR_azure_devops_pat_token }} - TF_VAR_azure_devops_url_organization: ${{ secrets.TF_VAR_azure_devops_url_organization }} - - -jobs: - build: - - name: Build roverdev - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v1 - - name: Docker Hub Login - uses: Azure/docker-login@v1 - with: - # Container registry username - username: aztfmod - # Container registry password - password: ${{ secrets.docker_registry_password }} - # Container registry server url - login-server: https://index.docker.io/v1/ - - name: Build the rover - run: | - set -e - docker_tag=latest - echo ::set-env name=docker_tag::${docker_tag} - - # Build the rover base image - docker-compose build --build-arg versionRover="aztfmod/roverdev:$docker_tag" - - docker tag rover_rover aztfmod/roverdev:$docker_tag - - docker push aztfmod/roverdev:$docker_tag - - - name: Create Release - id: create_release - uses: actions/create-release@latest - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token - with: - tag_name: ${{ env.docker_tag }} - release_name: aztfmod/roverdev:${{ env.docker_tag }} - draft: true - prerelease: false \ No newline at end of file diff --git a/.github/workflows/master.yml b/.github/workflows/master.yml index 4771335e..289898c1 100644 --- a/.github/workflows/master.yml +++ b/.github/workflows/master.yml @@ -1,7 +1,7 @@ name: master on: - pull_request: + push: branches: - master @@ -16,7 +16,7 @@ jobs: uses: Azure/docker-login@v1 with: # Container registry username - username: aztfmod + username: aztfmod # Container registry password password: ${{ secrets.docker_registry_password }} # Container registry server url diff --git a/.github/workflows/vnext.yml b/.github/workflows/vnext.yml index cfda985e..1f1935c9 100644 --- a/.github/workflows/vnext.yml +++ b/.github/workflows/vnext.yml @@ -29,17 +29,17 @@ jobs: uses: Azure/docker-login@v1 with: # Container registry username - username: aztfmod + username: aztfmod # Container registry password password: ${{ secrets.docker_registry_password }} # Container registry server url login-server: https://index.docker.io/v1/ + - name: Set the rover version + run: | + echo "docker_tag=$(date +"%g%m.%d%H%M")" >> $GITHUB_ENV - name: Build the rover - run: | + run: | set -e - docker_tag=$(date +"%g%m.%d%H%M") - echo ::set-env name=docker_tag::${docker_tag} - # Build the rover base image docker-compose build --build-arg versionRover="aztfmod/roverdev:$docker_tag" @@ -56,8 +56,8 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # This token is provided by Actions, you do not need to create your own token with: - tag_name: ${{ env.docker_tag }} - release_name: aztfmod/roverdev:${{ env.docker_tag }} + tag_name: $docker_tag + release_name: aztfmod/roverdev:$docker_tag draft: true prerelease: false body: You can also use the latest vnext by using aztfmod/roverdev:vnext \ No newline at end of file diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 00000000..1851272c --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,21 @@ +# See http://pre-commit.com for more information +# See http://pre-commit.com/hooks.html for more hooks +repos: + - repo: git://github.com/antonbabenko/pre-commit-terraform + rev: v1.43.0 + hooks: + - id: terraform_fmt + # - id: terraform_docs + # - id: terraform_tflint + # - id: terraform_tfsec + - repo: git://github.com/pre-commit/pre-commit-hooks + rev: v3.3.0 + hooks: + - id: check-merge-conflict + - id: trailing-whitespace + - id: check-yaml + - id: check-added-large-files + # - repo: git://github.com/markdownlint/markdownlint + # rev: v0.9.0 + # hooks: + # - id: markdownlint \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index d7fd8bd6..8e64cecf 100644 --- a/Dockerfile +++ b/Dockerfile @@ -27,7 +27,6 @@ RUN yum makecache fast && \ openssh-clients \ openssl \ man \ - ansible \ which && \ yum -y update @@ -66,6 +65,7 @@ ARG versionJq ARG versionDockerCompose ARG versionTfsec ARG versionAnsible +ARG versionPacker ARG USERNAME=vscode ARG USER_UID=1000 @@ -83,9 +83,12 @@ ENV SSH_PASSWD=${SSH_PASSWD} \ versionDockerCompose=${versionDockerCompose} \ versionTfsec=${versionTfsec} \ versionAnsible=${versionAnsible} \ + versionPacker=${versionPacker} \ TF_DATA_DIR="/home/${USERNAME}/.terraform.cache" \ TF_PLUGIN_CACHE_DIR="/home/${USERNAME}/.terraform.cache/plugin-cache" - + + + RUN yum -y install \ make \ zlib-devel \ @@ -93,7 +96,9 @@ RUN yum -y install \ gettext \ bzip2 \ gcc \ - unzip && \ + unzip \ + sudo \ + openssh-server && \ # # Install git from source code # @@ -112,12 +117,25 @@ RUN yum -y install \ touch /var/run/docker.sock && \ chmod 666 /var/run/docker.sock && \ # + # Create USERNAME + # + echo "Creating ${USERNAME} user..." && \ + useradd --uid $USER_UID -m -G docker ${USERNAME} && \ + # # Install Terraform # echo "Installing terraform ${versionTerraform}..." && \ curl -sSL -o /tmp/terraform.zip https://releases.hashicorp.com/terraform/${versionTerraform}/terraform_${versionTerraform}_linux_amd64.zip 2>&1 && \ unzip -d /usr/bin /tmp/terraform.zip && \ chmod +x /usr/bin/terraform && \ + mkdir -p /home/${USERNAME}/.terraform.cache/plugin-cache && \ + # + # Install Packer + # + echo "Installing Packer ${versionPacker}..." && \ + curl -sSL -o /tmp/packer.zip https://releases.hashicorp.com/packer/${versionPacker}/packer_${versionPacker}_linux_amd64.zip 2>&1 && \ + unzip -d /usr/local/bin /tmp/packer.zip && \ + chmod +x /usr/local/bin/packer && \ # # Install Docker-Compose - required to rebuild the rover from the rover ;) # @@ -154,16 +172,6 @@ gpgkey=https://packages.microsoft.com/keys/microsoft.asc" > /etc/yum.repos.d/azu curl -L -o /usr/bin/jq https://github.com/stedolan/jq/releases/download/jq-${versionJq}/jq-linux64 && \ chmod +x /usr/bin/jq && \ # - # Install pre-commit - # - echo "Installing pre-commit ..." && \ - python3 -m pip install pre-commit && \ - # - # Install Ansible - # - echo "Installing Ansible ..." && \ - pip3 install --user https://github.com/ansible/ansible/archive/stable-${versionAnsible}.tar.gz && \ - # # Install tflint # echo "Installing tflint ..." && \ @@ -171,28 +179,45 @@ gpgkey=https://packages.microsoft.com/keys/microsoft.asc" > /etc/yum.repos.d/azu unzip -d /usr/bin /tmp/tflint.zip && \ chmod +x /usr/bin/tflint && \ # + # Install Ansible + # + echo "Installing Ansible ${versionAnsible}..." && \ + pip3 install ansible==${versionAnsible} && \ + # + # Install pre-commit + # + echo "Installing pre-commit ..." && \ + pip3 install pre-commit && \ + # + # Install yq + # + echo "Installing yq ..." && \ + pip3 install yq && \ + # # Clean-up rm -f /tmp/*.zip && rm -f /tmp/*.gz && \ rm -rfd /tmp/git-${versionGit} && \ - # - echo "Creating ${USERNAME} user..." && \ - useradd --uid $USER_UID -m -G docker ${USERNAME} && \ - # sudo usermod -aG docker ${USERNAME} && \ - mkdir -p /home/${USERNAME}/.vscode-server /home/${USERNAME}/.vscode-server-insiders /home/${USERNAME}/.ssh /home/${USERNAME}/.ssh-localhost /home/${USERNAME}/.azure /home/${USERNAME}/.terraform.cache /home/${USERNAME}/.terraform.cache/tfstates && \ - chown ${USER_UID}:${USER_GID} /home/${USERNAME}/.vscode-server* /home/${USERNAME}/.ssh /home/${USERNAME}/.ssh-localhost /home/${USERNAME}/.azure /home/${USERNAME}/.terraform.cache /home/${USERNAME}/.terraform.cache/tfstates && \ - yum install -y sudo && \ + # + # Create USERNAME home folder structure + # + mkdir -p /tf/caf \ + /tf/rover \ + /home/${USERNAME}/.ansible \ + /home/${USERNAME}/.azure \ + /home/${USERNAME}/.gnupg \ + /home/${USERNAME}/.packer.d \ + /home/${USERNAME}/.ssh \ + /home/${USERNAME}/.ssh-localhost \ + /home/${USERNAME}/.terraform.cache \ + /home/${USERNAME}/.terraform.cache/tfstates \ + /home/${USERNAME}/.vscode-server \ + /home/${USERNAME}/.vscode-server-insiders && \ + chown -R ${USER_UID}:${USER_GID} /home/${USERNAME} /tf/rover /tf/caf && \ + chmod 777 -R /home/${USERNAME} /tf/caf && \ + chmod 700 /home/${USERNAME}/.ssh && \ echo ${USERNAME} ALL=\(root\) NOPASSWD:ALL > /etc/sudoers.d/${USERNAME} && \ chmod 0440 /etc/sudoers.d/${USERNAME} -# ssh server for Azure ACI -RUN yum install -y openssh-server && \ - rm -f /etc/ssh/ssh_host_ecdsa_key /etc/ssh/ssh_host_rsa_key /home/${USERNAME}/.ssh/ssh_host_ecdsa_key && \ - ssh-keygen -q -N "" -t ecdsa -b 521 -f /home/${USERNAME}/.ssh/ssh_host_ecdsa_key && \ - mkdir -p /home/${USERNAME}/.ssh - -COPY ./scripts/sshd_config /home/${USERNAME}/.ssh/sshd_config - - # Add Community terraform providers COPY --from=tfsec /go/bin/tfsec /bin/ COPY --from=terraform-docs /go/bin/terraform-docs /bin/ @@ -205,13 +230,24 @@ COPY ./scripts/clone.sh . COPY ./scripts/sshd.sh . COPY --from=rover_version version.txt /tf/rover/version.txt +# +# Switch to ${USERNAME} context +# + +USER ${USERNAME} + + +COPY ./scripts/sshd_config /home/${USERNAME}/.ssh/sshd_config + RUN echo "alias rover=/tf/rover/rover.sh" >> /home/${USERNAME}/.bashrc && \ echo "alias t=/usr/bin/terraform" >> /home/${USERNAME}/.bashrc && \ - mkdir -p /tf/caf && \ - chown -R ${USERNAME}:1000 /tf/rover /tf/caf /home/${USERNAME}/.ssh && \ - chmod +x /tf/rover/sshd.sh + # chmod +x /tf/rover/sshd.sh && \ + # + # ssh server for Azure ACI + # + ssh-keygen -q -N "" -t ecdsa -b 521 -f /home/${USERNAME}/.ssh/ssh_host_ecdsa_key + -USER ${USERNAME} EXPOSE 22 CMD ["/tf/rover/sshd.sh"] diff --git a/docker-compose.yml b/docker-compose.yml index 86de8434..c038dfbb 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -24,6 +24,7 @@ services: - versionTfsec - versionTerraformDocs - versionAnsible + - versionPacker volumes: - ..:/tf diff --git a/scripts/functions.sh b/scripts/functions.sh index 6a5b3e58..6c84ea8a 100644 --- a/scripts/functions.sh +++ b/scripts/functions.sh @@ -206,11 +206,8 @@ function initialize_state { echo "calling plan and apply" plan apply - # Create sandpit workspace + get_storage_id - - # workspace create "sandpit" - # workspace create ${TF_VAR_workspace} upload_tfstate ;; "validate") @@ -226,6 +223,8 @@ function initialize_state { ;; esac + rm -rf backend.azurerm.tf + cd "${current_path}" } @@ -244,6 +243,8 @@ function deploy_from_remote_state { deploy_landingzone + rm -rf backend.azurerm.tf + cd "${current_path}" } @@ -313,7 +314,6 @@ function upload_tfstate { export access_key=$(az storage account keys list --account-name ${storage_account_name} --resource-group ${resource_group} -o json | jq -r .[0].value) && echo " - storage_key: retrieved" # end=`date -u -d "30 minutes" '+%Y-%m-%dT%H:%MZ'` # sas=$(az storage account generate-sas --services b --resource-types sco --expiry $end --account-name ${storage_account_name} --permissions aclruw) - export access_key=$(az storage account keys list --account-name ${storage_account_name} --resource-group ${resource_group} -o json | jq -r .[0].value) && echo " - storage_key: retrieved" az storage blob upload -f "${TF_DATA_DIR}/tfstates/${TF_VAR_level}/${TF_VAR_workspace}/${TF_VAR_tf_name}" \ -c ${TF_VAR_workspace} \ @@ -368,46 +368,42 @@ function login_as_launchpad { echo " - keyvault_name: ${keyvault}" - export SECRET_PREFIX=$(az keyvault secret show -n launchpad-secret-prefix --vault-name ${keyvault} -o json | jq -r .value) && echo " - Name: ${SECRET_PREFIX}" - + stg=$(az storage account show --ids ${id} -o json) + + echo "" + echo "Getting launchpad coordinates:" + + export ARM_SUBSCRIPTION_ID=$(az keyvault secret show -n subscription-id --vault-name ${keyvault} -o json | jq -r .value) && echo " - subscription id: ${ARM_SUBSCRIPTION_ID}" + # If the logged in user does not have access to the launchpad - if [ "${SECRET_PREFIX}" == "" ]; then + if [ "${ARM_SUBSCRIPTION_ID}" == "" ]; then error 326 "Not authorized to manage landingzones. User must be member of the security group to access the launchpad and deploy a landing zone" 102 fi - - stg=$(az storage account show --ids ${id} -o json) + export TF_VAR_tenant_id=$(az keyvault secret show -n tenant-id --vault-name ${keyvault} -o json | jq -r .value) && echo " - tenant_id : ${TF_VAR_tenant_id}" - echo "" - echo "Getting launchpad coordinates:" - export TF_VAR_tfstate_storage_account_name=$(echo ${stg} | jq -r .name) && echo " - storage_account_name: ${TF_VAR_tfstate_storage_account_name}" - export TF_VAR_lowerlevel_storage_account_name=${TF_VAR_tfstate_storage_account_name} + export TF_VAR_tfstate_storage_account_name=$(echo ${stg} | jq -r .name) && echo " - storage_account_name (current): ${TF_VAR_tfstate_storage_account_name}" + export TF_VAR_lower_storage_account_name=$(az keyvault secret show -n lower-storage-account-name --vault-name ${keyvault} -o json 2>/dev/null | jq -r .value || true) && echo " - storage_account_name (lower): ${TF_VAR_lower_storage_account_name}" - export TF_VAR_tfstate_resource_group_name=$(echo ${stg} | jq -r .resourceGroup) && echo " - resource_group: ${TF_VAR_tfstate_resource_group_name}" - export TF_VAR_lowerlevel_resource_group_name=${TF_VAR_tfstate_resource_group_name} + export TF_VAR_tfstate_resource_group_name=$(echo ${stg} | jq -r .resourceGroup) && echo " - resource_group (current): ${TF_VAR_tfstate_resource_group_name}" + export TF_VAR_lower_resource_group_name=$(az keyvault secret show -n lower-resource-group-name --vault-name ${keyvault} -o json 2>/dev/null | jq -r .value || true) && echo " - resource_group (lower): ${TF_VAR_lower_resource_group_name}" export TF_VAR_tfstate_container_name=${TF_VAR_workspace} - export TF_VAR_lowerlevel_container_name=$(az keyvault secret show -n launchpad-blob-container --vault-name ${keyvault} -o json | jq -r .value) && echo " - container: ${TF_VAR_lowerlevel_container_name}" - + export TF_VAR_lower_container_name=${TF_VAR_workspace} + export TF_VAR_tfstate_key=${TF_VAR_tf_name} - export TF_VAR_lowerlevel_key=$(az keyvault secret show -n launchpad-blob-name --vault-name ${keyvault} -o json | jq -r .value) && echo " - tfstate file: ${TF_VAR_lowerlevel_key}" + - export ARM_SUBSCRIPTION_ID=$(az keyvault secret show -n launchpad-subscription-id --vault-name ${keyvault} -o json | jq -r .value) && echo " - subscription id: ${ARM_SUBSCRIPTION_ID}" - launchpad_mode=$(az keyvault secret show -n launchpad-mode --vault-name ${keyvault} -o json | jq -r .value) && echo " - launchpad mode: ${launchpad_mode}" + if [ ${caf_command} == "landingzone" ]; then - if [ ${caf_command} == "landingzone" ] && [ ${launchpad_mode} == "launchpad" ]; then - - echo "Set terraform provider context to Azure AD application launchpad " - export ARM_CLIENT_ID=$(az keyvault secret show -n ${SECRET_PREFIX}-client-id --vault-name ${keyvault} -o json | jq -r .value) && echo " - client id: ${ARM_CLIENT_ID}" - export ARM_CLIENT_SECRET=$(az keyvault secret show -n ${SECRET_PREFIX}-client-secret --vault-name ${keyvault} -o json | jq -r .value) - export ARM_TENANT_ID=$(az keyvault secret show -n ${SECRET_PREFIX}-tenant-id --vault-name ${keyvault} -o json | jq -r .value) && echo " - tenant id: ${ARM_TENANT_ID}" - export TF_VAR_logged_aad_app_objectId=$(az ad sp show --id ${ARM_CLIENT_ID} --query objectId -o tsv) && echo " - Set logged in aad app object id from keyvault: ${TF_VAR_logged_aad_app_objectId}" - - if [ ${TF_VAR_lowerlevel_key} == ${TF_VAR_tf_name} ] && [ ${tf_action} == "destroy" ]; then - error "You must run the rover in launchpad mode to destroy the launchpad" - fi - if [ ${impersonate} = true ]; then + export SECRET_PREFIX=$(az keyvault secret show -n launchpad-secret-prefix --vault-name ${keyvault} -o json | jq -r .value) && echo " - Name: ${SECRET_PREFIX}" + echo "Set terraform provider context to Azure AD application launchpad " + export ARM_CLIENT_ID=$(az keyvault secret show -n ${SECRET_PREFIX}-client-id --vault-name ${keyvault} -o json | jq -r .value) && echo " - client id: ${ARM_CLIENT_ID}" + export ARM_CLIENT_SECRET=$(az keyvault secret show -n ${SECRET_PREFIX}-client-secret --vault-name ${keyvault} -o json | jq -r .value) + export ARM_TENANT_ID=$(az keyvault secret show -n ${SECRET_PREFIX}-tenant-id --vault-name ${keyvault} -o json | jq -r .value) && echo " - tenant id: ${ARM_TENANT_ID}" + export TF_VAR_logged_aad_app_objectId=$(az ad sp show --id ${ARM_CLIENT_ID} --query objectId -o tsv) && echo " - Set logged in aad app object id from keyvault: ${TF_VAR_logged_aad_app_objectId}" + echo "Impersonating with the azure session with the launchpad service principal to deploy the landingzone" az login --service-principal -u ${ARM_CLIENT_ID} -p ${ARM_CLIENT_SECRET} --tenant ${ARM_TENANT_ID} fi @@ -510,9 +506,9 @@ function destroy { get_logged_user_object_id - if [ $(whoami) == "vscode" ] && [ ${TF_VAR_user_type} != "user" ] && [ "${caf_command}" == "launchpad" ]; then - error "You must be connected with the user who did the original launchpad initialization to destroy it" - fi + # if [ $(whoami) == "vscode" ] && [ ${TF_VAR_user_type} != "user" ] && [ "${caf_command}" == "launchpad" ]; then + # error "You must be connected with the user who did the original launchpad initialization to destroy it" + # fi rm -f "${TF_DATA_DIR}/terraform.tfstate" sudo rm -f ${landingzone_name}/backend.azurerm.tf @@ -524,7 +520,7 @@ function destroy { fi if [ -z "${ARM_USE_MSI}" ]; then - export ARM_ACCESS_KEY=$(az storage account keys list --account-name ${TF_VAR_lowerlevel_storage_account_name} --resource-group ${TF_VAR_lowerlevel_resource_group_name} -o json | jq -r .[0].value) + export ARM_ACCESS_KEY=$(az storage account keys list --account-name ${TF_VAR_tfstate_storage_account_name} --resource-group ${TF_VAR_tfstate_resource_group_name} -o json | jq -r .[0].value) # end=`date -u -d "600 minutes" '+%Y-%m-%dT%H:%MZ'` # export ARM_SAS_TOKEN=$(az storage account generate-sas --services b --resource-types sco --expiry $end --account-name ${TF_VAR_lowerlevel_storage_account_name} --permissions acdplruw) # export ARM_SAS_TOKEN=$(az storage container generate-sas --name ${TF_VAR_workspace} --expiry $end --account-name ${TF_VAR_lowerlevel_storage_account_name} --permissions acdlrw --auth-mode login --as-user) @@ -536,14 +532,18 @@ function destroy { -backend=true \ -get-plugins=true \ -upgrade=true \ - -backend-config storage_account_name=${TF_VAR_lowerlevel_storage_account_name} \ + -backend-config storage_account_name=${TF_VAR_tfstate_storage_account_name} \ + -backend-config resource_group_name=${TF_VAR_tfstate_resource_group_name} \ -backend-config container_name=${TF_VAR_workspace} \ -backend-config key=${TF_VAR_tf_name} \ ${landingzone_name} RETURN_CODE=$? && echo "Line ${LINENO} - Terraform init return code ${RETURN_CODE}" - terraform destroy ${tf_command} ${landingzone_name} + terraform destroy \ + -refresh=false \ + ${tf_command} \ + ${landingzone_name} RETURN_CODE=$? if [ $RETURN_CODE != 0 ]; then @@ -572,8 +572,9 @@ function destroy { mkdir -p "${TF_DATA_DIR}/tfstates/${TF_VAR_level}/${TF_VAR_workspace}" terraform destroy ${tf_command} \ - -state="${TF_DATA_DIR}/tfstates/${TF_VAR_level}/${TF_VAR_workspace}/${TF_VAR_tf_name}" \ - ${landingzone_name} + -refresh=false \ + -state="${TF_DATA_DIR}/tfstates/${TF_VAR_level}/${TF_VAR_workspace}/${TF_VAR_tf_name}" \ + ${landingzone_name} RETURN_CODE=$? if [ $RETURN_CODE != 0 ]; then @@ -655,22 +656,22 @@ function deploy_landingzone { mkdir -p "${TF_DATA_DIR}/tfstates/${TF_VAR_level}/${TF_VAR_workspace}" - if [ -z "${ARM_USE_MSI}" ]; then - export ARM_ACCESS_KEY=$(az storage account keys list --account-name ${TF_VAR_lowerlevel_storage_account_name} --resource-group ${TF_VAR_lowerlevel_resource_group_name} -o json | jq -r .[0].value) - # end=`date -u -d "600 minutes" '+%Y-%m-%dT%H:%MZ'` - # export ARM_SAS_TOKEN=$(az storage account generate-sas --services b --resource-types sco --expiry $end --account-name ${TF_VAR_lowerlevel_storage_account_name} --permissions acdplruw) - # export ARM_SAS_TOKEN=$(az storage container generate-sas --name ${TF_VAR_workspace} --expiry $end --account-name ${TF_VAR_lowerlevel_storage_account_name} --permissions acdlrw --auth-mode login --as-user) - fi + # if [ -z "${ARM_USE_MSI}" ]; then + # # export ARM_ACCESS_KEY=$(az storage account keys list --account-name ${TF_VAR_tfstate_storage_account_name} --resource-group ${TF_VAR_tfstate_resource_group_name} -o json | jq -r .[0].value) + # # end=`date -u -d "600 minutes" '+%Y-%m-%dT%H:%MZ'` + # # export ARM_SAS_TOKEN=$(az storage account generate-sas --services b --resource-types sco --expiry $end --account-name ${TF_VAR_lowerlevel_storage_account_name} --permissions acdplruw) + # # export ARM_SAS_TOKEN=$(az storage container generate-sas --name ${TF_VAR_workspace} --expiry $end --account-name ${TF_VAR_lowerlevel_storage_account_name} --permissions acdlrw --auth-mode login --as-user) + # fi terraform init \ -reconfigure=true \ -backend=true \ -get-plugins=true \ -upgrade=true \ - -backend-config storage_account_name=${TF_VAR_lowerlevel_storage_account_name} \ + -backend-config storage_account_name=${TF_VAR_tfstate_storage_account_name} \ + -backend-config resource_group_name=${TF_VAR_tfstate_resource_group_name} \ -backend-config container_name=${TF_VAR_workspace} \ -backend-config key=${TF_VAR_tf_name} \ - -backend-config access_key=${ARM_ACCESS_KEY} \ ${landingzone_name} RETURN_CODE=$? && echo "Terraform init return code ${RETURN_CODE}" @@ -797,9 +798,9 @@ function clean_up_variables { echo "@calling clean_up_variables" echo "cleanup variables" - unset TF_VAR_lowerlevel_storage_account_name - unset TF_VAR_lowerlevel_resource_group_name - unset TF_VAR_lowerlevel_key + unset TF_VAR_lower_storage_account_name + unset TF_VAR_lower_resource_group_name + unset TF_VAR_lower_key unset LAUNCHPAD_NAME unset ARM_TENANT_ID unset ARM_SUBSCRIPTION_ID @@ -829,6 +830,7 @@ function get_logged_user_object_id { unset ARM_CLIENT_SECRET unset TF_VAR_logged_aad_app_objectId + export TF_VAR_tenant_id=$(az account show | jq -r .tenantId) export TF_VAR_logged_user_objectId=$(az ad signed-in-user show --query objectId -o tsv) export logged_user_upn=$(az ad signed-in-user show --query userPrincipalName -o tsv) echo " - logged in user objectId: ${TF_VAR_logged_user_objectId} (${logged_user_upn})" @@ -838,20 +840,29 @@ function get_logged_user_object_id { unset TF_VAR_logged_user_objectId export clientId=$(az account show --query user.name -o tsv) + export keyvault=$(az keyvault list --query "[?tags.tfstate=='${TF_VAR_level}' && tags.environment=='${TF_VAR_environment}']" -o json | jq -r .[0].name) + case "${clientId}" in "systemAssignedIdentity") echo " - logged in Azure with System Assigned Identity" ;; "userAssignedIdentity") - echo " - logged in Azure wiht User Assigned Identity: ($(az account show -o json | jq -r .user.assignedIdentityInfo))" + echo " - logged in Azure with User Assigned Identity: ($(az account show -o json | jq -r .user.assignedIdentityInfo))" + msi=$(az account show | jq -r .user.assignedIdentityInfo) + export TF_VAR_logged_aad_app_objectId=$(az identity show --ids ${msi//MSIResource-} | jq -r .principalId) + export TF_VAR_logged_user_objectId=$(az identity show --ids ${msi//MSIResource-} | jq -r .principalId) && echo " Logged in rover msi object_id: ${TF_VAR_logged_user_objectId}" + export ARM_TENANT_ID=$(az keyvault secret show -n tenant-id --vault-name ${keyvault} -o json | jq -r .value) && echo " - tenant_id : ${ARM_TENANT_ID}" ;; *) # When connected with a service account the name contains the objectId export TF_VAR_logged_aad_app_objectId=$(az ad sp show --id ${clientId} --query objectId -o tsv) && echo " Logged in rover app object_id: ${TF_VAR_logged_aad_app_objectId}" + export TF_VAR_logged_user_objectId=$(az ad sp show --id ${clientId} --query objectId -o tsv) && echo " Logged in rover app object_id: ${TF_VAR_logged_aad_app_objectId}" echo " - logged in Azure AD application: $(az ad sp show --id ${clientId} --query displayName -o tsv)" ;; esac + export TF_VAR_tenant_id=${ARM_TENANT_ID} + fi } @@ -961,7 +972,10 @@ function get_storage_id { fi exit 1000 else - echo "There is no launchpad in the environment: ${TF_VAR_environment}" + echo + echo "There is no remote state for ${TF_VAR_level} in the environment: ${TF_VAR_environment}" + echo "You need to update the launchpad configuration and add an additional level or deploy in the level0." + echo echo "List of the other launchpad deployed" az storage account list --query "[?tags.tfstate=='${TF_VAR_level}'].{name:name,environment:tags.environment, launchpad:tags.launchpad}" -o table @@ -969,3 +983,34 @@ function get_storage_id { fi fi } + +function expand_tfvars_folder { + + echo " Expanding variable files: ${1}/*.tfvars" + + for filename in "${1}"/*.tfvars; do + if [ "${filename}" != "${1}/*.tfvars" ]; then + PARAMS+="-var-file ${filename} " + fi + done + +} + +# +# This function verifies the vscode container is running the version specified in the docker-compose +# of the .devcontainer sub-folder +# +function verify_rover_version { + user=$(whoami) + + if [ "${user}" = "vscode" ]; then + required_version=$(cat /tf/caf/.devcontainer/docker-compose.yml | yq | jq -r .services.rover.image) + running_version=$(cat /tf/rover/version.txt) + + if [ "${required_version}" != "${running_version}" ]; then + echo "The version of your local devcontainer ${running_version} does not match the required version ${required_version}." + echo "Click on the Dev Container buttom on the left bottom corner and select rebuild container from the options." + exit + fi + fi +} diff --git a/scripts/rover.sh b/scripts/rover.sh index 04effffa..fc4e7fa2 100755 --- a/scripts/rover.sh +++ b/scripts/rover.sh @@ -9,6 +9,8 @@ source /tf/rover/clone.sh source /tf/rover/functions.sh source /tf/rover/banner.sh +verify_rover_version + export TF_VAR_workspace=${TF_VAR_workspace:="tfstate"} export TF_VAR_environment=${TF_VAR_environment:="sandpit"} export TF_VAR_rover_version=$(echo $(cat /tf/rover/version.txt)) @@ -18,6 +20,7 @@ export ARM_SNAPSHOT=${ARM_SNAPSHOT:="true"} export ARM_STORAGE_USE_AZUREAD=${ARM_STORAGE_USE_AZUREAD:="true"} export impersonate=${impersonate:=false} export LC_ALL=en_US.UTF-8 +unset PARAMS current_path=$(pwd) @@ -105,6 +108,10 @@ while (( "$#" )); do export impersonate=true shift 1 ;; + -var-folder) + expand_tfvars_folder ${2} + shift 2 + ;; *) # preserve positional arguments PARAMS+="${1} " shift @@ -129,9 +136,4 @@ echo "workspace : '$(echo ${TF_VAR_workspace})'" echo "tfstate : '$(echo ${TF_VAR_tf_name})'" echo "" -if [ $(whoami) != "vscode" ] && [ "${caf_command}" == "landingzone" ]; then - export impersonate=true - echo "Impersonating the rover to service principal" -fi - process_actions