--- variables: PHASE: BUILD CICD_MODE: "true" GIT_SUBMODULE_STRATEGY: "recursive" PRINT_DEBUG: "false" {% if TF_TOKEN_MODULE_ACCESS %} {{ TF_TOKEN_MODULE_ACCESS_KEY }}: {{ TF_TOKEN_MODULE_ACCESS_VALUE }} {% endif %} # Docker Image Tag TFLINT_IMAGE_TAG: {{ environ('TFLINT_IMAGE_TAG') }} PRECOMMIT_IMAGE_TAG: {{ environ('PRECOMMIT_IMAGE_TAG') }} TFENV_IMAGE_TAG: {{ environ('TFENV_IMAGE_TAG') }} DRIFTCTL_IMAGE_TAG: {{ environ('DRIFTCTL_IMAGE_TAG') }} # NEED TO BE CHANGED FOR EACH PROJECT PROJECT_NAME: {{ environ('PROJECT_NAME') }} REGION: {{ environ('REGION') }} TF_VAR_assume_role: {{ environ('CICD_ROLE_NAME') }} TF_VAR_backend_bucket_name: {{ environ('TF_VAR_backend_bucket_name') }} TF_VAR_backend_bucket_region: {{ environ('REGION') }} TF_VAR_backend_dynamodb_table: {{ environ('TF_VAR_backend_dynamodb_table')}} TF_VAR_backend_bucket_access_role: "arn:aws:iam::{{ environ('ACCOUNT_ID') }}:role/{{ environ('CICD_ROLE_NAME') }}" PLAN_BINARY_FILE: {{ environ('PLAN_BINARY_FILE') }} PLAN_JSON_FILE: {{ environ('PLAN_JSON_FILE') }} ACCOUNT_ID: {{ environ('ACCOUNT_ID') }} CICD_ROLE_NAME: {{ environ('CICD_ROLE_NAME') }} {%- set plans_install = environ('PLAN_INSTALL_LIST').split(',') -%} {%- set plans_delete = environ('PLAN_DELETE_LIST').split(',') %} {%- set runners = environ('CICD_RUNNER_TAGS').split(',') %} cache: key: $CI_COMMIT_REF_SLUG paths: - creds.env stages: - aws-creds - quality-checks - drift - plan - tests - apply - delete - clean-cache ######################################################################################################################## # FUNCTIONS ######################################################################################################################## .aws-cli: before_script: - yum install -y jq image: name: amazon/aws-cli:latest entrypoint: - '/usr/bin/env' - 'PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin' tags: {% for runner in runners %} - {{ runner }} {% endfor %} .aws_get_creds: &aws_get_creds script: | #!/usr/bin/env bash echo "Getting temporary credentials associated to assume role" STS_CREDS=$(aws sts assume-role --role-arn arn:aws:iam::903534291474:role/Vocalcom-CiCd-CrossAccountRole --role-session-name ${CI_COMMIT_SHA}) AWS_ACCESS_KEY_ID=$(echo $STS_CREDS | jq -r '.Credentials.AccessKeyId') AWS_SECRET_ACCESS_KEY=$(echo $STS_CREDS | jq -r '.Credentials.SecretAccessKey') AWS_SESSION_TOKEN=$(echo $STS_CREDS | jq -r '.Credentials.SessionToken') echo "export AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID" > creds.env echo "export AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY" >> creds.env echo "export AWS_SESSION_TOKEN=$AWS_SESSION_TOKEN" >> creds.env .terraform-base: before_script: - rm -rf .terraform image: name: marmarama/tfenv:$TFENV_IMAGE_TAG entrypoint: - '/usr/bin/env' - 'PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/tfenv/bin/' tags: {% for runner in runners %} - {{ runner }} {% endfor %} {% if GITLAB_JOBS["terraform-trivy"] %} .terraform-trivy: before_script: - rm -rf .terraform - . ./creds.env - apk --no-cache --update add make image: name: aquasec/trivy:latest entrypoint: - '/usr/bin/env' - 'PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/tfenv/bin/' tags: {% for runner in runners %} - {{ runner }} {% endfor %} {% endif %} {% if GITLAB_JOBS["terraform-lint"] %} .terraform-lint: image: name: ghcr.io/terraform-linters/tflint:${TFLINT_IMAGE_TAG} entrypoint: - '/usr/bin/env' - 'PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin' before_script: - apk --no-cache --update add make tags: {% for runner in runners %} - {{ runner }} {% endfor %} {% endif %} {% if GITLAB_JOBS["shell-lint"] %} .shelllint: image: name: pipelinecomponents/shellcheck:latest entrypoint: - '/usr/bin/env' - 'PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin' tags: {% for runner in runners %} - {{ runner }} {% endfor %} {% endif %} {% if GITLAB_JOBS["precommit"] %} .precommit: image: name: ghcr.io/antonbabenko/pre-commit-terraform:${PRECOMMIT_IMAGE_TAG} entrypoint: - '/usr/bin/env' - 'PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin' tags: {% for runner in runners %} - {{ runner }} {% endfor %} {% endif %} {% if GITLAB_JOBS["yaml-lint"] %} .yamllint: image: name: pipelinecomponents/yamllint:latest entrypoint: - '/usr/bin/env' - 'PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin' before_script: - apk --no-cache --update add make tags: {% for runner in runners %} - {{ runner }} {% endfor %} {% endif %} {% if GITLAB_JOBS["terraform-compliance"] %} .terraform-compliance: image: name: eerkunt/terraform-compliance:latest entrypoint: - '/usr/bin/env' - 'PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin' before_script: - apt-get update && apt-get install -y make - . ./creds.env tags: {% for runner in runners %} - {{ runner }} {% endfor %} {% endif %} {% if GITLAB_JOBS["terraform-terrascan"] %} .terraform-terrascan: image: name: tenable/terrascan:latest entrypoint: - '/usr/bin/env' - 'PATH=/go/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin' before_script: - . ./creds.env tags: {% for runner in runners %} - {{ runner }} {% endfor %} {% endif %} {% if GITLAB_JOBS["md-lint"] %} .md_lint: image: name: pipelinecomponents/markdownlint:latest entrypoint: - '/usr/bin/env' - 'PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/app/bin' before_script: - apk --no-cache --update add make - . ./creds.env tags: {% for runner in runners %} - {{ runner }} {% endfor %} {% endif %} ######################################################################################################################## # COMMONS ######################################################################################################################## {% if GITLAB_JOBS["aws-creds"] %} aws-creds: extends: .aws-cli stage: aws-creds <<: *aws_get_creds {% endif %} {% if GITLAB_JOBS["terraform-compliance"] %} ######################################################################################################################## # TESTS ######################################################################################################################## terraform-compliance: needs: [plan_all] extends: .terraform-compliance allow_failure: true stage: tests script: - make terraform_compliance {% endif %} ######################################################################################################################## # QUALITY CHECKS ######################################################################################################################## {% if GITLAB_JOBS["terraform-lint"] %} terraform-lint: needs: [] extends: .terraform-lint allow_failure: true stage: quality-checks script: - make lint {% endif %} {% if GITLAB_JOBS["precommit"] %} precommit: needs: [] extends: .precommit allow_failure: true stage: quality-checks before_script: - apk --no-cache --update add make script: - make precommit {% endif %} {% if GITLAB_JOBS["terraform-format"] %} terraform-format: needs: [] extends: .terraform-base allow_failure: true stage: quality-checks script: - make format {% endif %} {% if GITLAB_JOBS["terraform-validate"] %} terraform-validate: needs: [] extends: .terraform-base allow_failure: true before_script: - . ./creds.env stage: quality-checks script: - make validate {% endif %} {% if GITLAB_JOBS["terraform-terrascan"] %} terraform-terrascan: needs: [] extends: .terraform-terrascan allow_failure: true stage: quality-checks script: - terrascan scan -i terraform --verbose --config-path=./.terrascan_config.toml {% for plan_name in plans_install %} --iac-dir={{ plan_name }}{% endfor %} {% endif %} {% if GITLAB_JOBS["md-lint"] %} md-lint: needs: [] extends: .md_lint allow_failure: true stage: quality-checks script: - make markdown_lint {% endif %} {% if GITLAB_JOBS["shell-lint"] %} shell-lint: needs: [] extends: .shelllint allow_failure: true before_script: - . ./creds.env - apk --no-cache --update add make stage: quality-checks script: - make shell_lint {% endif %} {% if GITLAB_JOBS["yaml-lint"] %} yaml-lint: needs: [] extends: .yamllint allow_failure: true stage: quality-checks script: - make yaml_lint {% endif %} {% if GITLAB_JOBS["terraform-trivy"] %} terraform-trivy: needs: [] extends: .terraform-trivy allow_failure: true stage: quality-checks script: - make trivy {% endif %} {% if GITLAB_JOBS["driftctl"] %} ######################################################################################################################## # DRIFT Detection ######################################################################################################################## driftctl: stage: drift needs: [aws-creds] allow_failure: true image: name: snyk/driftctl:$DRIFTCTL_IMAGE_TAG entrypoint: [""] variables: AWS_DEFAULT_REGION: $REGION ROLE_TO_ASSUME: ${TF_VAR_backend_bucket_access_role} AWS_ROLE_SESSION_NAME: "sessiondrifctl" before_script: - . ./creds.env - apk add --no-cache aws-cli - apk add --no-cache jq script: | #!/usr/bin/env bash echo "Getting temporary credentials associated to assume role" aws sts get-caller-identity STS_CREDS=$(aws sts assume-role --role-arn ${ROLE_TO_ASSUME} --role-session-name ${AWS_ROLE_SESSION_NAME}) AWS_ACCESS_KEY_ID=$(echo $STS_CREDS | jq -r '.Credentials.AccessKeyId') AWS_SECRET_ACCESS_KEY=$(echo $STS_CREDS | jq -r '.Credentials.SecretAccessKey') AWS_SESSION_TOKEN=$(echo $STS_CREDS | jq -r '.Credentials.SessionToken') aws sts get-caller-identity driftctl scan --only-managed --from tfstate+s3://"${TF_VAR_backend_bucket_name}"/*.tfstate {% endif %} ######################################################################################################################## # PLAN ######################################################################################################################## .plan_job: &plan_job extends: .terraform-base stage: plan needs: [aws-creds] allow_failure: false before_script: - . ./creds.env {% for plan_name in plans_install +%} {% set path = plan_name.split('/') %} {% set slug = plan_name.replace('/',"_") %} plan_{{ slug }}: <<: *plan_job script: - make plan_{{ slug }} artifacts: paths: - {{ plan_name }}/{{ environ('PLAN_BINARY_FILE') }} - {{ plan_name }}/{{ environ('PLAN_JSON_FILE') }} only: changes: - {{ plan_name }}/**/* {% endfor %} {% if GITLAB_JOBS["plan_all"] %} plan_all: <<: *plan_job script: - make plan_all artifacts: paths: - ./**/{{ environ('PLAN_BINARY_FILE') }} - ./**/{{ environ('PLAN_JSON_FILE') }} {% endif %} ######################################################################################################################## # APPLY ######################################################################################################################## .apply_job: &apply_job extends: .terraform-base stage: apply allow_failure: false when: manual before_script: - . ./creds.env {% for plan_name in plans_install +%} {% set path = plan_name.split('/') %} {% set slug = plan_name.replace('/',"_") %} apply_{{ slug }}: <<: *apply_job needs: [plan_{{ slug }}] script: - make install_{{ slug }} only: {% if TF_APPLY_ONLY_MAIN %} refs: - main {% endif %} changes: - {{ plan_name }}/**/* {% endfor %} {% if GITLAB_JOBS["apply_all"] %} apply_all: <<: *apply_job needs: [plan_all] script: - make install_all {% if TF_APPLY_ONLY_MAIN %} only: refs: - main {% endif %} {% endif %} ######################################################################################################################## # DELETE ######################################################################################################################## .delete_job: &delete_job extends: .terraform-base allow_failure: false stage: delete when: manual before_script: - . ./creds.env only: variables: - $PHASE == "DESTROY" {% for plan_name in plans_delete +%} {% set path = plan_name.split('/') %} {% set slug = plan_name.replace('/',"_") %} delete_{{ slug}}: <<: *delete_job script: - make delete_{{ slug }} {% endfor %} {% if GITLAB_JOBS["delete_all"] %} delete_all: <<: *delete_job script: - make delete_all {% endif %}