diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index a4969c80..f6a0ee91 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -15,8 +15,10 @@ // 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": { - // If you are using an Alpine-based image, change this to /bin/ash - "terminal.integrated.shell.linux": "/bin/bash" + "files.eol": "\n", + "terminal.integrated.shell.linux": "/bin/bash", + "editor.tabSize": 2, + "terminal.integrated.scrollback": 2000, }, // Uncomment the next line if you want start specific services in your Docker Compose config. @@ -31,6 +33,7 @@ // Add the IDs of extensions you want installed when the container is created in the array below. "extensions": [ "4ops.terraform", - "mutantdino.resourcemonitor" + "mutantdino.resourcemonitor", + "eamodio.gitlens" ] } \ No newline at end of file diff --git a/.devcontainer/docker-compose.yml b/.devcontainer/docker-compose.yml index 41e946d1..00fcfada 100644 --- a/.devcontainer/docker-compose.yml +++ b/.devcontainer/docker-compose.yml @@ -6,8 +6,8 @@ version: '3.7' services: rover: - image: aztfmod/roverdev:vnext - + image: aztfmod/rover:latest + labels: - "caf=Azure CAF" diff --git a/.env b/.env index 99ab761e..2d69cffe 100644 --- a/.env +++ b/.env @@ -1,11 +1,10 @@ -versionTerraform=0.12.28 -versionAzureCli=2.7.0 -versionKubectl=v1.18.2 -versionGit=2.25.0 -versionTflint=v0.16.2 +versionTerraform=0.12.29 +versionAzureCli=2.9.1 +versionKubectl=v1.18.6 +versionGit=2.27.0 +versionTflint=v0.18.0 versionJq=1.6 versionDockerCompose=1.25.5 -versionLaunchpadOpensource=master versionAzureCafTerraform=v.0.3.1 -versionTfsec=v0.21.0 +versionTfsec=v0.24.1 versionTerraformDocs=v0.9.1 \ No newline at end of file diff --git a/.github/workflows/vnext.yml b/.github/workflows/vnext.yml index 518d669d..f3db5532 100644 --- a/.github/workflows/vnext.yml +++ b/.github/workflows/vnext.yml @@ -52,10 +52,10 @@ jobs: - name: Build the rover (beta 0.13) run: | set -e - docker_tag=vnext-13-beta2 + docker_tag=vnext-13-rc1 # Override .env variable - export versionTerraform="0.13.0-beta2" + export versionTerraform="0.13.0-rc1" # Build the rover base image docker-compose build --build-arg versionRover="aztfmod/roverdev:$docker_tag" diff --git a/.gitignore b/.gitignore index 771d7988..da04f020 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ **/~*.* **/*.log version.txt +landingzones diff --git a/Dockerfile b/Dockerfile index def6879d..62b8fe3d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -50,18 +50,6 @@ FROM golang:1.13 as tfsec # to force the docker cache to invalidate when there is a new version RUN env GO111MODULE=on go get -u github.com/liamg/tfsec/cmd/tfsec -# ########################################################### -# # Getting latest version of Azure DevOps Terraform provider -# ########################################################### -# FROM golang:1.13 as devops - -# # to force the docker cache to invalidate when there is a new version -# ADD https://api.github.com/repos/microsoft/terraform-provider-azuredevops/git/refs/heads/master version.json -# RUN cd /tmp && \ -# git clone https://github.com/microsoft/terraform-provider-azuredevops.git && \ -# cd terraform-provider-azuredevops && \ -# ./scripts/build.sh - ########################################################### # Getting latest version of Azure CAF Terraform provider ########################################################### @@ -104,21 +92,22 @@ ARG versionTflint ARG versionGit ARG versionJq ARG versionDockerCompose -ARG versionLaunchpadOpensource ARG versionTfsec ARG USERNAME=vscode ARG USER_UID=1000 ARG USER_GID=${USER_UID} +ARG SSH_PASSWD -ENV versionTerraform=${versionTerraform} \ +ENV SSH_PASSWD=${SSH_PASSWD} \ + USERNAME=${USERNAME} \ + versionTerraform=${versionTerraform} \ versionAzureCli=${versionAzureCli} \ versionKubectl=${versionKubectl} \ versionTflint=${versionTflint} \ versionJq=${versionJq} \ versionGit=${versionGit} \ versionDockerCompose=${versionDockerCompose} \ - versionLaunchpadOpensource=${versionLaunchpadOpensource} \ versionTfsec=${versionTfsec} \ TF_DATA_DIR="/home/${USERNAME}/.terraform.cache" \ TF_PLUGIN_CACHE_DIR="/home/${USERNAME}/.terraform.cache/plugin-cache" @@ -146,6 +135,8 @@ RUN yum -y install \ # yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo && \ yum -y install docker-ce-cli && \ + touch /var/run/docker.sock && \ + chmod 666 /var/run/docker.sock && \ # # Install Terraform # @@ -194,11 +185,6 @@ gpgkey=https://packages.microsoft.com/keys/microsoft.asc" > /etc/yum.repos.d/azu echo "Installing pre-commit ..." && \ python3 -m pip install pre-commit && \ # - # Install graphviz - # - # echo "Installing graphviz ..." && \ - # yum -y install graphviz && \ - # # Install tflint # echo "Installing tflint ..." && \ @@ -219,18 +205,16 @@ gpgkey=https://packages.microsoft.com/keys/microsoft.asc" > /etc/yum.repos.d/azu 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 -# to force the docker cache to invalidate when there is a new version -ADD https://api.github.com/repos/aztfmod/level0/git/refs/heads/${versionLaunchpadOpensource} version.json -RUN echo "cloning the launchpads version ${versionLaunchpadOpensource}" && \ - mkdir -p /tf && \ - git clone https://github.com/aztfmod/level0.git /tf --branch ${versionLaunchpadOpensource} && \ - chown -R ${USERNAME}:1000 /tf/launchpads && \ - chmod +x /tf/bootstrap/**/*.sh && \ - chmod +x /tf/bootstrap/*.sh # Add Community terraform providers -# COPY --from=devops /tmp/terraform-provider-azuredevops/bin /bin/ COPY --from=azurecaf /tmp/terraform-provider-azurecaf/terraform-provider-azurecaf /bin/ COPY --from=msgraph /tmp/terraform-provider-msgraph/terraform-provider-msgraph /bin/ COPY --from=tfsec /go/bin/tfsec /bin/ @@ -238,14 +222,19 @@ COPY --from=terraform-docs /go/bin/terraform-docs /bin/ WORKDIR /tf/rover COPY ./scripts/rover.sh . -COPY ./scripts/launchpad.sh . COPY ./scripts/functions.sh . COPY ./scripts/banner.sh . +COPY ./scripts/clone.sh . +COPY ./scripts/sshd.sh . COPY --from=rover_version version.txt /tf/rover/version.txt RUN echo "alias rover=/tf/rover/rover.sh" >> /home/${USERNAME}/.bashrc && \ - echo "alias launchpad=/tf/rover/launchpad.sh" >> /home/${USERNAME}/.bashrc && \ echo "alias t=/usr/bin/terraform" >> /home/${USERNAME}/.bashrc && \ - chown -R ${USERNAME}:1000 /tf/rover + mkdir -p /tf/caf && \ + chown -R ${USERNAME}:1000 /tf/rover /tf/caf /home/${USERNAME}/.ssh && \ + chmod +x /tf/rover/sshd.sh USER ${USERNAME} + +EXPOSE 22 +CMD ["/tf/rover/sshd.sh"] \ No newline at end of file diff --git a/changelog.md b/changelog.md index 4483330d..a6fde8cf 100644 --- a/changelog.md +++ b/changelog.md @@ -1,4 +1,35 @@ -## 2002.dev (Unrelease) +## 2007.dev (Unrelease) + +NEW COMMANDS +* Launchpad commands moved into the rover with +```bash +rover /tf/caf/landingzones/launchpad apply -launchpad +``` + +* Clone the public launchpad folder +```bash +# Clone the public open source launchpad from master branch +rover --clone-launchpad + +# Clone the public open source launchpad from vnext branch +rover --clone-launchpad --clone-branch vnext +``` + +* Clone the public landingzones folder (includes the launchpad) +```bash +# Clone the public open source landingzones from master branch +rover --clone-landingzones + +# Clone the public open source landingzones from vnext branch +rover --clone-landingzones --clone-branch vnext +``` + +REMOVED COMMANDS +* launchpad.sh as now been replaced with +``` +# Clone the launchpad with the new clone command +rover launchpad_path plan -launchpad +``` # v2002 refresh diff --git a/docker-compose.yml b/docker-compose.yml index 8283ecff..47c26600 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -20,7 +20,6 @@ services: - versionTflint - versionJq - versionDockerCompose - - versionLaunchpadOpensource - versionAzureCafTerraform - versionRover - versionTfsec diff --git a/scripts/clone.sh b/scripts/clone.sh new file mode 100644 index 00000000..a1158d02 --- /dev/null +++ b/scripts/clone.sh @@ -0,0 +1,153 @@ +#!/bin/bash + +export clone_destination=${clone_destination:="/tf/caf/landingzones"} +export clone_folder=${clone_folder:="/"} +export clone_folder_strip=${clone_folder_strip:=2} +export clone_project_name=${clone_project_name:="Azure/caf-terraform-landingzones"} +export landingzone_branch=${landingzone_branch:="master"} + +current_path=$(pwd) + + +function display_clone_instructions { + + while (( "$#" )); do + case "${1}" in + --intro) + echo + echo "Rover clone is used to bring the landing zones dependencies you need to deploy your landing zone" + echo + shift 1 + ;; + --clone) + display_clone_instructions --intro --examples --clone-branch --clone-destination --clone-folder --clone-folder-strip + echo "--clone specify a GitHub organization and project in the for org/project" + echo " The default setting if not set is azure/caf-terraform-landingzones" + echo + shift 1 + ;; + --clone-branch) + echo "--clone-branch set the branch to pull the package." + echo " By default is not set use the master branch." + echo + shift 1 + ;; + --clone-destination) + echo "--clone-destination change the destination local folder." + echo " By default clone the package into the /tf/caf/landingzones folder of the rover" + echo + shift 1 + ;; + --clone-folder) + echo "--clone-folder specify the folder to extract from the original project" + echo + echo " Example: --clone-folder /landingzones/landingzone_caf_foundations will only extract the caf foundations landing zone" + echo + shift 1 + ;; + --clone-folder-strip) + echo "--clone-folder-strip is used strip the base folder structure from the original folder" + echo + echo " In the GitHub package of azure/caf-terraform-landingzones, the data are packaged in the following structure" + echo " caf-terraform-landingzones-master/landingzones/launchpad/main.tf" + echo " [project]-[branch]/landgingzones/[landingzone]" + echo " To reproduce a nice folder structure in the rover it it possible to set the --clone-folder-strip to 2 to remove [project]-[branch]/landingzones and only retrieve the third level folder" + echo "" + echo " Default to 2 when using azure/caf-terraform-landingzones and 1 for all other git projects" + echo + shift 1 + ;; + --examples) + echo "By default the rover will clone the azure/caf-terraform-landingzones into the local rover folder /tf/caf/landinzones" + echo + echo "Examples:" + echo " - Clone the launchpad: rover --clone-folder /landingzones/launchpad" + echo " - Clone the launchpad in different folder: rover --clone-destination /tf/caf/landingzones/public --clone-folder /landingzones/launchpad" + echo " - Clone the launchpad (branch vnext): rover --clone-folder-strip 2 --clone-destination /tf/rover/landingzones --clone-folder /landingzones/launchpad --clone-branch vnext" + echo + echo " - Clone the CAF foundations landingzone: rover --clone-folder /landingzones/landingzone_caf_foundations" + echo " - Clone the AKS landingzone: rover --clone aztfmod/landingzone_aks --clone-destination /tf/caf/landingzones/landingzone_aks" + echo + echo + shift 1 + ;; + esac + done +} + + +function clone_repository { + echo "@calling clone_repository" + + url="https://codeload.github.com/${clone_project_name}/tar.gz/${landingzone_branch}" + + echo + echo "clone_project_name : ${clone_project_name}" + echo "landingzone_branch : ${landingzone_branch}" + echo "clone_folder : ${clone_folder}" + echo "clone_folder_strip : ${clone_folder_strip}" + echo "clone_destination : ${clone_destination}" + echo "clone_url : ${url}" + echo "" + + rm -rf ${clone_destination}/$(basename ${clone_folder}) + mkdir -p ${clone_destination} + + curl https://codeload.github.com/${clone_project_name}/tar.gz/${landingzone_branch} --fail --silent --show-error | tar -zxv --strip=${clone_folder_strip} -C ${clone_destination} "$(basename ${clone_project_name})-${landingzone_branch}${clone_folder}" + + echo + echo "Clone complete" + echo +} + +function process_clone_parameter { + echo "@calling process_clone_parameter with $@" + + + case "${1}" in + --clone) + if [ $# -eq 1 ]; then + display_clone_instructions ${1} + exit 21 + else + export caf_command="clone" + export landingzone_branch=${landingzone_branch:="master"} + export clone_project_name=${2} + export clone_folder_strip=1 + fi + ;; + --clone-branch) + echo $# + if [ $# -eq 1 ]; then + display_clone_instructions ${1} + exit 22 + else + export landingzone_branch=${2} + fi + ;; + --clone-destination) + if [ $# -eq 1 ]; then + display_clone_instructions ${1} + exit 23 + else + export clone_destination=${2} + fi + ;; + --clone-folder) + if [ $# -eq 1 ]; then + display_clone_instructions ${1} + exit 24 + else + export clone_folder=${2} + fi + ;; + --clone-folder-strip) + if [ $# -eq 1 ]; then + display_clone_instructions ${1} + exit 24 + else + export clone_folder_strip=${2} + fi + ;; + esac +} diff --git a/scripts/functions.sh b/scripts/functions.sh index d240a9bd..cf348d21 100644 --- a/scripts/functions.sh +++ b/scripts/functions.sh @@ -25,10 +25,36 @@ exit_if_error() { } } +function process_actions { + echo "@calling process_actions" + verify_azure_session + + case "${caf_command}" in + workspace) + workspace ${tf_command} + exit 0 + ;; + clone) + clone_repository + exit 0 + ;; + landingzone_mgmt) + landing_zone ${tf_command} + exit 0 + ;; + launchpad|landingzone) + verify_parameters + deploy ${TF_VAR_workspace} + ;; + *) + display_instructions + esac +} + function display_login_instructions { echo "" echo "To login the rover to azure:" - echo " rover login [tenant_name.onmicrosoft.com or tenant_guid (optional)] [subscription_id_to_target(optional)]" + echo " rover login -tenant [tenant_name.onmicrosoft.com or tenant_guid (optional)] -subscription [subscription_id_to_target(optional)]" echo "" echo " rover logout" echo "" @@ -40,7 +66,7 @@ function display_login_instructions { function display_instructions { echo "" echo "You can deploy a landingzone with the rover by running:" - echo " rover [landingzone_folder_name] [plan|apply|destroy]" + echo " rover -lz [landingzone_folder_name] -a [plan|apply|destroy|validate]" echo "" echo "List of the landingzones loaded in the rover:" @@ -58,7 +84,11 @@ function display_instructions { function display_launchpad_instructions { echo "" echo "You need to deploy the launchpad from the rover by running:" - echo " rover /tf/caf/landingzones/launchpad apply -launchpad" + if [ -z "${TF_VAR_environment}" ]; then + echo " rover -lz /tf/caf/landingzones/launchpad -a apply -launchpad" + else + echo " rover -lz /tf/caf/landingzones/launchpad -a apply -launchpad -env ${TF_VAR_environment}" + fi echo "" } @@ -66,10 +96,23 @@ function display_launchpad_instructions { function verify_parameters { echo "@calling verify_parameters" - # Must provide an action when the tf_command is set - if [ -z "${tf_action}" ] && [ ! -z "${tf_command}" ]; then - display_instructions - error ${LINENO} "landingzone and action must be set" 11 + if [ -z "${landingzone_name}" ]; then + echo "landingzone : '' (not specified)" + if [ ${caf_command} == "launchpad" ]; then + display_instructions + error ${LINENO} "action must be set when deploying a landing zone" 11 + fi + else + echo "landingzone : '$(echo ${landingzone_name})'" + cd ${landingzone_name} + export TF_VAR_tf_name=${TF_VAR_tf_name:="$(basename $(pwd)).tfstate"} + export TF_VAR_tf_plan=${TF_VAR_tf_plan:="$(basename $(pwd)).tfplan"} + + # Must provide an action when the tf_command is set + if [ -z "${tf_action}" ]; then + display_instructions + error ${LINENO} "action must be set when deploying a landing zone" 11 + fi fi } @@ -78,7 +121,7 @@ function verify_parameters { function verify_azure_session { echo "@calling verify_azure_session" - if [ "${landingzone_name}" == "login" ]; then + if [ "${caf_command}" == "login" ]; then echo "" echo "Checking existing Azure session" session=$(az account show 2>/dev/null || true) @@ -89,24 +132,24 @@ function verify_azure_session { unset ARM_CLIENT_ID unset ARM_CLIENT_SECRET - if [ ! -z "${tf_action}" ]; then - echo "Login to azure with tenant ${tf_action}" - ret=$(az login --tenant ${tf_action} >/dev/null >&1) + if [ ! -z "${tenant}" ]; then + echo "Login to azure with tenant ${tenant}" + ret=$(az login --tenant ${tenant} >/dev/null >&1) else ret=$(az login >/dev/null >&1) fi # the second parameter would be the subscription id to target - if [ "${tf_command}" != "login" ] && [ ! -z "${tf_command}" ]; then - echo "Set default subscription to ${tf_command}" - az account set -s ${tf_command} + if [ ! -z "${subscription}" ]; then + echo "Set default subscription to ${subscription}" + az account set -s ${subscription} fi az account show exit fi - if [ "${landingzone_name}" == "logout" ]; then + if [ "${caf_command}" == "logout" ]; then echo "Closing Azure session" az logout || true @@ -129,28 +172,28 @@ function verify_azure_session { } -# Verifies the landingzone exist in the rover -function verify_landingzone { - echo "@calling verifiy_landingzone" - - if [ -z "${landingzone_name}" ] && [ -z "${tf_action}" ] && [ -z "${tf_command}" ]; then - # get_remote_state_details - login_as_launchpad - - if [ -z ${TF_VAR_lowerlevel_storage_account_name} ]; then - display_launchpad_instructions - else - display_instructions - fi - else - echo "Verify the landingzone folder exist in the rover" - readlink -f "${landingzone_name}" - if [ $? -ne 0 ]; then - display_instructions - error ${LINENO} "landingzone does not exist" 12 - fi - fi -} +# # Verifies the landingzone exist in the rover +# function verify_landingzone { +# echo "@calling verifiy_landingzone" + +# if [ -z "${landingzone_name}" ] && [ -z "${tf_action}" ] && [ -z "${tf_command}" ]; then +# # get_remote_state_details +# login_as_launchpad + +# if [ -z ${TF_VAR_lowerlevel_storage_account_name} ]; then +# display_launchpad_instructions +# else +# display_instructions +# fi +# else +# echo "Verify the landingzone folder exist in the rover" +# readlink -f "${landingzone_name}" +# if [ $? -ne 0 ]; then +# display_instructions +# error ${LINENO} "landingzone does not exist" 12 +# fi +# fi +# } function initialize_state { echo "@calling initialize_state" @@ -187,8 +230,8 @@ function initialize_state { # Create sandpit workspace get_storage_id - workspace_create "sandpit" - workspace_create ${TF_VAR_workspace} + workspace create "sandpit" + workspace create ${TF_VAR_workspace} upload_tfstate ;; "validate") @@ -221,8 +264,6 @@ function deploy_from_remote_state { login_as_launchpad - # get_launchpad_coordinates - deploy_landingzone cd "${current_path}" @@ -332,7 +373,7 @@ function list_deployed_landingzones { -c ${TF_VAR_workspace} \ --account-key ${access_key} \ --account-name ${storage_account_name} -o json | \ - jq -r '["lnanding zone", "size in Kb", "last modification"], (.[] | [.name, .properties.contentLength / 1024, .properties.lastModified]) | @csv' | \ + jq -r '["landing zone", "size in Kb", "last modification"], (.[] | [.name, .properties.contentLength / 1024, .properties.lastModified]) | @csv' | \ awk 'BEGIN{ FS=OFS="," }NR>1{ $2=sprintf("%.2f",$2) }1' | \ column -t -s ',' @@ -371,16 +412,20 @@ function login_as_launchpad { 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 [ ${launchpad_mode} == "launchpad" ]; then - echo "Set terraform provider context to Azure AD application launchpad " + # if [ ${caf_command} == "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}" + # fi + + 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}" - fi - - if [ ${caf_command} == "rover" ] && [ ${launchpad_mode} == "launchpad" ]; then - echo "rover mode" 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 @@ -416,7 +461,7 @@ function login_as_launchpad_1510 { 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}" - if [ ${caf_command} == "rover" ] && [ "${caf_launchpad}" == "launchpad_opensource" ]; then + if [ ${caf_command} == "landingzone" ] && [ "${launchpad_mode}" == "launchpad_opensource" ]; then echo "" echo "Impersonating with the launchpad service principal to deploy the landingzone" @@ -524,7 +569,7 @@ function destroy { get_logged_user_object_id - if [ $(whoami) == "vscode" ] && [ ${TF_VAR_user_type} != "user" ] && [ "${caf_command}" == "launchpad" ] && []; then + 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 @@ -658,21 +703,17 @@ function deploy_landingzone { mkdir -p "${TF_DATA_DIR}/tfstates/${TF_VAR_workspace}" - # get_remote_state_details - # login_as_launchpad - 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) - terraform init \ - -reconfigure \ - -backend=true \ - -get-plugins=true \ - -upgrade=true \ - -backend-config storage_account_name=${TF_VAR_lowerlevel_storage_account_name} \ - -backend-config container_name=${TF_VAR_workspace} \ - -backend-config access_key=${ARM_ACCESS_KEY} \ - -backend-config key=${TF_VAR_tf_name} + -reconfigure \ + -backend=true \ + -get-plugins=true \ + -upgrade=true \ + -backend-config storage_account_name=${TF_VAR_lowerlevel_storage_account_name} \ + -backend-config container_name=${TF_VAR_workspace} \ + -backend-config access_key=${ARM_ACCESS_KEY} \ + -backend-config key=${TF_VAR_tf_name} RETURN_CODE=$? && echo "Terraform init return code ${RETURN_CODE}" @@ -707,6 +748,32 @@ function deploy_landingzone { ##### workspace functions +## Workspaces are used for an additional level of isolation. Mainly used by CI +function workspace { + + echo "@calling workspace function with $@" + get_storage_id + + if [ "${id}" == "null" ]; then + display_launchpad_instructions + exit 1000 + fi + + case "${1}" in + "list") + workspace_list + ;; + "create") + workspace_create ${2} + ;; + "delete") + workspace_delete ${2} + ;; + *) + echo "launchpad workspace [ list | create | delete ]" + ;; + esac +} function workspace_list { echo "@calling workspace_list" @@ -747,6 +814,26 @@ function workspace_create { echo "" } +function workspace_delete { + echo "@calling workspace_delete" + + stg=$(az storage account show --ids ${id} -o json) + + export storage_account_name=$(echo ${stg} | jq -r .name) + + echo " Delete $1 workspace" + echo "" + az storage container delete \ + --name $1 \ + --auth-mode login \ + --account-name ${storage_account_name} + + mkdir -p ${TF_DATA_DIR}/tfstates/${TF_VAR_workspace} + + echo "" +} + + function clean_up_variables { echo "@calling clean_up_variables" @@ -759,6 +846,7 @@ function clean_up_variables { unset ARM_TENANT_ID unset ARM_SUBSCRIPTION_ID unset ARM_CLIENT_ID + unset ARM_USE_MSI unset TF_VAR_rover_pilot_application_id unset ARM_CLIENT_SECRET unset TF_VAR_logged_user_objectId @@ -804,6 +892,7 @@ function get_logged_user_object_id { function deploy { + get_storage_id case "${id}" in "null") @@ -846,8 +935,8 @@ function deploy { if [ -e "${TF_DATA_DIR}/tfstates/${TF_VAR_workspace}/${TF_VAR_tf_name}" ]; then echo "Recover from an un-finished previous execution" if [ "${tf_action}" == "destroy" ]; then - if [ "${caf_command}" == "rover" ]; then - login_as_launchpad + if [ "${caf_command}" == "landingzone" ]; then + login_as_launchpad fi destroy else @@ -859,12 +948,10 @@ function deploy { "destroy") destroy_from_remote_state ;; - "plan"|"apply") + "plan"|"apply"|"validate") deploy_from_remote_state ;; *) - login_as_launchpad - # get_launchpad_coordinates display_instructions ;; esac @@ -876,45 +963,47 @@ function deploy { } function landing_zone { - case "${tf_action}" in - "list") - echo "Listing the deployed landing zones" - list_deployed_landingzones - ;; - *) - echo "launchpad landing_zone [ list | unlock [landing_zone_tfstate_name]]" - ;; - esac -} - -## Workspaces are used to isolate environments like sandpit, dev, sit, production -function workspace { - - if [ "${id}" == "null" ]; then - display_launchpad_instructions - exit 1000 - fi + echo "@calling landing_zone" + + get_storage_id - case "${tf_action}" in - "list") - workspace_list - ;; - "create") - workspace_create ${tf_command} - ;; - "delete") - ;; - *) - echo "launchpad workspace [ list | create | delete ]" - ;; - esac + case "${1}" in + "list") + echo "Listing the deployed landing zones" + list_deployed_landingzones + ;; + *) + echo "rover landingzone [ list ]" + ;; + esac } + function get_storage_id { echo "@calling get_storage_id" #1510 launchpad version id=$(az storage account list --query "[?tags.tfstate=='level0' && tags.workspace=='level0']" -o json | jq -r .[0].id) if [ ${id} == null ]; then id=$(az storage account list --query "[?tags.tfstate=='${TF_VAR_level}' && tags.environment=='${TF_VAR_environment}'].{id:id}" -o json | jq -r .[0].id) + if [ ${id} == null ] && [ "${caf_command}" != "launchpad" ]; then + # Check if other launchpad are installed + id=$(az storage account list --query "[?tags.tfstate=='${TF_VAR_level}'].{id:id}" -o json | jq -r .[0].id) + + if [ ${id} == null ]; then + if [ ${TF_VAR_level} != "level0" ]; then + echo "Multi-level support is not yet support. Coming soon." + else + display_launchpad_instructions + fi + exit 1000 + else + echo "There is no launchpad in the environment: ${TF_VAR_environment}" + 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 + + exit 0 + fi + fi fi } + diff --git a/scripts/launchpad.sh b/scripts/launchpad.sh deleted file mode 100755 index b034aec5..00000000 --- a/scripts/launchpad.sh +++ /dev/null @@ -1,163 +0,0 @@ -#!/bin/bash - -# capture the current path -export TF_VAR_rover_version="$(echo $(cat /tf/rover/version.txt))" -current_path=$(pwd) -landingzone_name=$1 -tf_action=$2 -shift 2 - -export TF_VAR_workspace="level0" -export caf_command="launchpad" - - -while (( "$#" )); do - case "$1" in - -o|--output) - tf_output_file=$2 - shift 2 - ;; - *) # preserve positional arguments - echo "else $1" - - PARAMS+="$1 " - shift - ;; - esac -done - -tf_command=$(echo $PARAMS | sed -e 's/^[ \t]*//') - -echo "" -echo "Launchpad management tool started with:" -echo " tool is : '$(echo ${caf_command})'" -echo " tf_action is : '$(echo ${tf_action})'" -echo " tf_command is : '$(echo ${tf_command})'" -echo " landingzone is : '$(echo ${landingzone_name})'" -echo " workspace is : '$(echo ${TF_VAR_workspace})'" -echo "" - - -set -ETe -trap 'error ${LINENO}' ERR 1 2 3 6 - -source /tf/rover/functions.sh -source /tf/rover/banner.sh - -verify_azure_session - - - -# Trying to retrieve the terraform state storage account id -id=$(az storage account list --query "[?tags.tfstate=='level0' && tags.workspace=='level0']" -o json | jq -r .[0].id) - -function launchpad_opensource { - - case "${id}" in - "null") - echo "No launchpad found." - - if [ "${tf_action}" == "destroy" ]; then - if [ -e "${TF_DATA_DIR}/tfstates/${TF_VAR_workspace}/$(basename ${landingzone_name}).tfstate" ]; then - echo "Recover from an un-finished initialisation" - destroy - else - rm -rf "${TF_DATA_DIR}/tfstates/${TF_VAR_workspace}" - echo "There is no launchpad in this subscription" - fi - else - echo "Deploying from scratch the launchpad" - rm -rf "${TF_DATA_DIR}/tfstates/${TF_VAR_workspace}" - initialize_state - display_instructions - fi - ;; - '') - error ${LINENO} "you must login to an Azure subscription first or logout / login again" 2 - ;; - *) - - if [ -e "${TF_DATA_DIR}/tfstates/${TF_VAR_workspace}/$(basename ${landingzone_name}).tfstate" ]; then - echo "Recover from an un-finished initialisation" - if [ "${tf_action}" == "destroy" ]; then - destroy - else - initialize_state - fi - exit 0 - else - case "${tf_action}" in - "destroy") - destroy_from_remote_state - ;; - "plan"|"apply") - deploy_from_remote_state - ;; - *) - get_launchpad_coordinates - display_instructions - ;; - esac - fi - ;; - esac - - -} - -function landing_zone { - case "${tf_action}" in - "list") - echo "Listing the deployed landing zones" - list_deployed_landingzones - ;; - *) - echo "launchpad landing_zone [ list | unlock [landing_zone_tfstate_name]]" - ;; - esac -} - -## Workspaces are used to isolate environments like sandpit, dev, sit, production -function workspace { - - if [ "${id}" == "null" ]; then - display_launchpad_instructions - exit 1000 - fi - - case "${tf_action}" in - "list") - workspace_list - ;; - "create") - workspace_create ${tf_command} - ;; - "delete") - ;; - *) - echo "launchpad workspace [ list | create | delete ]" - ;; - esac -} - -case "${landingzone_name}" in - "landing_zone") - landing_zone - ;; - "workspace") - workspace - ;; - "") - if [ "${id}" == "null" ]; then - display_launchpad_instructions - exit 1000 - else - get_launchpad_coordinates - display_instructions - fi - ;; - *) - launchpad_opensource "level0" -esac - -clean_up_variables \ No newline at end of file diff --git a/scripts/rover.sh b/scripts/rover.sh index a2777ccb..c627e331 100755 --- a/scripts/rover.sh +++ b/scripts/rover.sh @@ -3,108 +3,122 @@ # Initialize the launchpad first with rover # deploy a landingzone with -# rover [landingzone_folder_name] [plan | apply | destroy] [parameters] +# rover -lz [landingzone_folder_name] -a [plan | apply | destroy] [parameters] -current_path=$(pwd) -landingzone_name=$1 -tf_action=$2 -shift 2 - -cd ${landingzone_name} +source /tf/rover/clone.sh +source /tf/rover/functions.sh +source /tf/rover/banner.sh -# capture the current path export TF_VAR_workspace=${TF_VAR_workspace:="sandpit"} export TF_VAR_environment=${TF_VAR_environment:="sandpit"} export TF_VAR_rover_version=$(echo $(cat /tf/rover/version.txt)) -export TF_VAR_tf_name=${TF_VAR_tf_name:="$(basename $(pwd)).tfstate"} -export TF_VAR_tf_plan=${TF_VAR_tf_plan:="$(basename $(pwd)).tfplan"} export TF_VAR_level=${TF_VAR_level:="level0"} -export caf_command="rover" +export TF_DATA_DIR=${TF_DATA_DIR:="/home/vscode"} +export LC_ALL=en_US.UTF-8 +current_path=$(pwd) while (( "$#" )); do - case "${1}" in - -o|--output) - tf_output_file=${2} - shift 2 - ;; - -w|--workspace) - export TF_VAR_workspace=${2} + case "${1}" in + --clone|--clone-branch|--clone-folder|--clone-destination|--clone-folder-strip) + export caf_command="clone" + process_clone_parameter $@ + shift 2 + ;; + -lz|--landingzone) + export caf_command="landingzone" + export landingzone_name=${2} + export TF_VAR_tf_name=${TF_VAR_tf_name:="$(basename ${landingzone_name}).tfstate"} + shift 2 + ;; + -a|--action) + export tf_action=${2} + shift 2 + ;; + --clone-launchpad) + export caf_command="clone" + export landingzone_branch=${landingzone_branch:="master"} + export clone_launchpad="true" + export clone_landingzone="false" + echo "cloning launchpad" + shift 1 + ;; + workspace) + shift 1 + export caf_command="workspace" + ;; + landingzone) + shift 1 + export caf_command="landingzone_mgmt" + ;; + login) + shift 1 + export caf_command="login" + ;; + -t|--tenant) + export tenant=${2} + shift 2 + ;; + -s|--subscription) + export subscription=${2} + shift 2 + ;; + logout) + shift 1 + export caf_command="logout" + ;; + -tfstate) + export TF_VAR_tf_name=${2} + if [ ${TF_VAR_tf_name##*.} != "tfstate" ]; then + echo "tfstate name extension must be .tfstate" + exit 50 + fi + export TF_VAR_tf_plan="${TF_VAR_tf_name%.*}.tfplan" shift 2 - echo "set workspace to ${TF_VAR_workspace}" ;; -env|--environment) export TF_VAR_environment=${2} shift 2 ;; - -tfstate) - export TF_VAR_tf_name="${2}.tfstate" - export TF_VAR_tf_plan="${2}.tfplan" - shift 2 - ;; - -level) - export TF_VAR_level=${2} - shift 2 - ;; -launchpad) export caf_command="launchpad" export TF_VAR_workspace="level0" shift 1 - echo "set rover to mode ${caf_command}" - echo "set workspace to level0" + ;; + -o|--output) + tf_output_file=${2} + shift 2 + ;; + -w|--workspace) + export TF_VAR_workspace=${2} + shift 2 + ;; + -l|-level) + export TF_VAR_level=${2} + shift 2 ;; *) # preserve positional arguments - PARAMS+="${1} " shift ;; esac done + set -ETe trap 'error ${LINENO}' ERR 1 2 3 6 -source /tf/rover/functions.sh -source /tf/rover/banner.sh - tf_command=$(echo $PARAMS | sed -e 's/^[ \t]*//') echo "" - echo "mode : '$(echo ${caf_command})'" +echo "terraform command output file : '$(echo ${tf_output_file})'" echo "tf_action : '$(echo ${tf_action})'" -echo "tf_command : '$(echo ${tf_command})'" -echo "landingzone : '$(echo ${landingzone_name})'" -echo "terraform command output file : '$(echo ${tf_output_file})' " -echo "level : '$(echo ${TF_VAR_level})'" +echo "command and parameters : '$(echo ${tf_command})'" +echo "level (current) : '$(echo ${TF_VAR_level})'" echo "environment : '$(echo ${TF_VAR_environment})'" -# echo "workspace : '$(echo ${TF_VAR_workspace})'" +echo "workspace : '$(echo ${TF_VAR_workspace})'" echo "tfstate : '$(echo ${TF_VAR_tf_name})'" echo "" -verify_azure_session -verify_parameters - -# Trying to retrieve the terraform state storage account id -get_storage_id - -case "${landingzone_name}" in - "landing_zone") - landing_zone - ;; - "workspace") - workspace - ;; - "") - if [ "${id}" == "null" ]; then - display_launchpad_instructions - exit 1000 - else - # login_as_launchpad - # get_launchpad_coordinates - display_instructions - fi - ;; - *) - deploy ${TF_VAR_workspace} -esac \ No newline at end of file +process_actions diff --git a/scripts/sshd.sh b/scripts/sshd.sh new file mode 100644 index 00000000..a9b7ae7e --- /dev/null +++ b/scripts/sshd.sh @@ -0,0 +1,15 @@ +#!/bin/bash +set -Eeo pipefail + + +echo "user ${USERNAME}" +echo "password ${SSH_PASSWD}" + +# Generate unique ssh keys , if needed +if [ ! -f /home/vscode/.ssh/ssh_host_ecdsa_key ]; then + ssh-keygen -t ecdsa -b 521 -f /home/vscode/.ssh/ssh_host_ecdsa_key -N '' +fi + +echo "${USERNAME}:${SSH_PASSWD}" | sudo chpasswd + +sudo /usr/sbin/sshd -f /home/vscode/.ssh/sshd_config -D -e \ No newline at end of file diff --git a/scripts/sshd_config b/scripts/sshd_config new file mode 100644 index 00000000..db089cd0 --- /dev/null +++ b/scripts/sshd_config @@ -0,0 +1,21 @@ +# +# /etc/ssh/sshd_config +# + +Port 22 +ListenAddress 0.0.0.0 +LoginGraceTime 180 +X11Forwarding yes +Ciphers aes256-ctr,aes128-ctr,aes192-ctr +KexAlgorithms ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521,diffie-hellman-group14-sha1,diffie-hellman-group-exchange-sha256 +StrictModes no +SyslogFacility DAEMON +PrintMotd no +IgnoreRhosts no +PasswordAuthentication yes +PermitEmptyPasswords no +PermitRootLogin no +UsePrivilegeSeparation no +#UsePam no +LogLevel VERBOSE +HostKey /home/vscode/.ssh/ssh_host_ecdsa_key diff --git a/workspace.code-workspace b/workspace.code-workspace deleted file mode 100644 index bc35ebc8..00000000 --- a/workspace.code-workspace +++ /dev/null @@ -1,11 +0,0 @@ -{ - "folders": [ - { - "path": "./" - } - ], - "settings": { - "files.eol": "\n" - }, - -} \ No newline at end of file