From c0d8ef519f4369b8fe75756b93b64e6bdbead902 Mon Sep 17 00:00:00 2001 From: Mathis Kappeler Date: Mon, 18 Dec 2023 16:55:25 +0100 Subject: [PATCH 1/5] test --- .github/CODE_OF_CONDUCT.md | 9 + .github/dependabot.yml | 11 + .github/workflows/tf-drift.yml | 174 +++++++++++ .github/workflows/tf-plan-apply.yml | 146 +++++++++ .github/workflows/tf-unit-tests.yml | 45 +++ .gitignore | 442 ++++++++++++++++++++++++++++ main.tf | 28 ++ terraform.tfvars | 3 + variables.tf | 2 + 9 files changed, 860 insertions(+) create mode 100644 .github/CODE_OF_CONDUCT.md create mode 100644 .github/dependabot.yml create mode 100644 .github/workflows/tf-drift.yml create mode 100644 .github/workflows/tf-plan-apply.yml create mode 100644 .github/workflows/tf-unit-tests.yml create mode 100644 .gitignore create mode 100644 main.tf create mode 100644 terraform.tfvars create mode 100644 variables.tf diff --git a/.github/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..f9ba8cf --- /dev/null +++ b/.github/CODE_OF_CONDUCT.md @@ -0,0 +1,9 @@ +# Microsoft Open Source Code of Conduct + +This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). + +Resources: + +- [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/) +- [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) +- Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..7602182 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,11 @@ +# To get started with Dependabot version updates, you'll need to specify which +# package ecosystems to update and where the package manifests are located. +# Please see the documentation for all configuration options: +# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates + +version: 2 +updates: + - package-ecosystem: "terraform" # See documentation for possible values + directory: "/" # Location of package manifests + schedule: + interval: "weekly" diff --git a/.github/workflows/tf-drift.yml b/.github/workflows/tf-drift.yml new file mode 100644 index 0000000..a92b2d3 --- /dev/null +++ b/.github/workflows/tf-drift.yml @@ -0,0 +1,174 @@ +name: 'Terraform Configuration Drift Detection' + +on: + workflow_dispatch: + schedule: + - cron: '41 3 * * *' # runs nightly at 3:41 am + +#Special permissions required for OIDC authentication +permissions: + id-token: write + contents: read + issues: write + +#These environment variables are used by the terraform azure provider to setup OIDD authenticate. +env: + ARM_CLIENT_ID: "${{ secrets.AZURE_CLIENT_ID }}" + ARM_SUBSCRIPTION_ID: "${{ secrets.AZURE_SUBSCRIPTION_ID }}" + ARM_TENANT_ID: "${{ secrets.AZURE_TENANT_ID }}" + +jobs: + terraform-plan: + name: 'Terraform Plan' + runs-on: ubuntu-latest + env: + #this is needed since we are running terraform with read-only permissions + ARM_SKIP_PROVIDER_REGISTRATION: true + outputs: + tfplanExitCode: ${{ steps.tf-plan.outputs.exitcode }} + + steps: + # Checkout the repository to the GitHub Actions runner + - name: Checkout + uses: actions/checkout@v3 + + # Install the latest version of the Terraform CLI + - name: Setup Terraform + uses: hashicorp/setup-terraform@v2 + with: + terraform_wrapper: false + + # Initialize a new or existing Terraform working directory by creating initial files, loading any remote state, downloading modules, etc. + - name: Terraform Init + run: terraform init + + # Generates an execution plan for Terraform + # An exit code of 0 indicated no changes, 1 a terraform failure, 2 there are pending changes. + - name: Terraform Plan + id: tf-plan + run: | + export exitcode=0 + terraform plan -detailed-exitcode -no-color -out tfplan || export exitcode=$? + + echo "exitcode=$exitcode" >> $GITHUB_OUTPUT + + if [ $exitcode -eq 1 ]; then + echo Terraform Plan Failed! + exit 1 + else + exit 0 + fi + + # Save plan to artifacts + - name: Publish Terraform Plan + uses: actions/upload-artifact@v3 + with: + name: tfplan + path: tfplan + + # Create string output of Terraform Plan + - name: Create String Output + id: tf-plan-string + run: | + TERRAFORM_PLAN=$(terraform show -no-color tfplan) + + delimiter="$(openssl rand -hex 8)" + echo "summary<<${delimiter}" >> $GITHUB_OUTPUT + echo "## Terraform Plan Output" >> $GITHUB_OUTPUT + echo "
Click to expand" >> $GITHUB_OUTPUT + echo "" >> $GITHUB_OUTPUT + echo '```terraform' >> $GITHUB_OUTPUT + echo "$TERRAFORM_PLAN" >> $GITHUB_OUTPUT + echo '```' >> $GITHUB_OUTPUT + echo "
" >> $GITHUB_OUTPUT + echo "${delimiter}" >> $GITHUB_OUTPUT + + # Publish Terraform Plan as task summary + - name: Publish Terraform Plan to Task Summary + env: + SUMMARY: ${{ steps.tf-plan-string.outputs.summary }} + run: | + echo "$SUMMARY" >> $GITHUB_STEP_SUMMARY + + # If changes are detected, create a new issue + - name: Publish Drift Report + if: steps.tf-plan.outputs.exitcode == 2 + uses: actions/github-script@v6 + env: + SUMMARY: "${{ steps.tf-plan-string.outputs.summary }}" + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const body = `${process.env.SUMMARY}`; + const title = 'Terraform Configuration Drift Detected'; + const creator = 'github-actions[bot]' + + // Look to see if there is an existing drift issue + const issues = await github.rest.issues.listForRepo({ + owner: context.repo.owner, + repo: context.repo.repo, + state: 'open', + creator: creator, + title: title + }) + + if( issues.data.length > 0 ) { + // We assume there shouldn't be more than 1 open issue, since we update any issue we find + const issue = issues.data[0] + + if ( issue.body == body ) { + console.log('Drift Detected: Found matching issue with duplicate content') + } else { + console.log('Drift Detected: Found matching issue, updating body') + github.rest.issues.update({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issue.number, + body: body + }) + } + } else { + console.log('Drift Detected: Creating new issue') + + github.rest.issues.create({ + owner: context.repo.owner, + repo: context.repo.repo, + title: title, + body: body + }) + } + + # If changes aren't detected, close any open drift issues + - name: Publish Drift Report + if: steps.tf-plan.outputs.exitcode == 0 + uses: actions/github-script@v6 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const title = 'Terraform Configuration Drift Detected'; + const creator = 'github-actions[bot]' + + // Look to see if there is an existing drift issue + const issues = await github.rest.issues.listForRepo({ + owner: context.repo.owner, + repo: context.repo.repo, + state: 'open', + creator: creator, + title: title + }) + + if( issues.data.length > 0 ) { + const issue = issues.data[0] + + github.rest.issues.update({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issue.number, + state: 'closed' + }) + } + + # Mark the workflow as failed if drift detected + - name: Error on Failure + if: steps.tf-plan.outputs.exitcode == 2 + run: exit 1 diff --git a/.github/workflows/tf-plan-apply.yml b/.github/workflows/tf-plan-apply.yml new file mode 100644 index 0000000..1e97900 --- /dev/null +++ b/.github/workflows/tf-plan-apply.yml @@ -0,0 +1,146 @@ +name: 'Terraform Plan/Apply' + +on: + push: + branches: + - main + pull_request: + branches: + - main + +#Special permissions required for OIDC authentication +permissions: + id-token: write + contents: read + pull-requests: write + +#These environment variables are used by the terraform azure provider to setup OIDD authenticate. +env: + ARM_CLIENT_ID: "${{ secrets.AZURE_CLIENT_ID }}" + ARM_SUBSCRIPTION_ID: "${{ secrets.AZURE_SUBSCRIPTION_ID }}" + ARM_TENANT_ID: "${{ secrets.AZURE_TENANT_ID }}" + +jobs: + terraform-plan: + name: 'Terraform Plan' + runs-on: ubuntu-latest + env: + #this is needed since we are running terraform with read-only permissions + ARM_SKIP_PROVIDER_REGISTRATION: true + outputs: + tfplanExitCode: ${{ steps.tf-plan.outputs.exitcode }} + + steps: + # Checkout the repository to the GitHub Actions runner + - name: Checkout + uses: actions/checkout@v3 + + # Install the latest version of the Terraform CLI + - name: Setup Terraform + uses: hashicorp/setup-terraform@v2 + with: + terraform_wrapper: false + + # Initialize a new or existing Terraform working directory by creating initial files, loading any remote state, downloading modules, etc. + - name: Terraform Init + run: terraform init + + # Checks that all Terraform configuration files adhere to a canonical format + # Will fail the build if not + - name: Terraform Format + run: terraform fmt -check + + # Generates an execution plan for Terraform + # An exit code of 0 indicated no changes, 1 a terraform failure, 2 there are pending changes. + - name: Terraform Plan + id: tf-plan + run: | + export exitcode=0 + terraform plan -detailed-exitcode -no-color -out tfplan || export exitcode=$? + + echo "exitcode=$exitcode" >> $GITHUB_OUTPUT + + if [ $exitcode -eq 1 ]; then + echo Terraform Plan Failed! + exit 1 + else + exit 0 + fi + + # Save plan to artifacts + - name: Publish Terraform Plan + uses: actions/upload-artifact@v3 + with: + name: tfplan + path: tfplan + + # Create string output of Terraform Plan + - name: Create String Output + id: tf-plan-string + run: | + TERRAFORM_PLAN=$(terraform show -no-color tfplan) + + delimiter="$(openssl rand -hex 8)" + echo "summary<<${delimiter}" >> $GITHUB_OUTPUT + echo "## Terraform Plan Output" >> $GITHUB_OUTPUT + echo "
Click to expand" >> $GITHUB_OUTPUT + echo "" >> $GITHUB_OUTPUT + echo '```terraform' >> $GITHUB_OUTPUT + echo "$TERRAFORM_PLAN" >> $GITHUB_OUTPUT + echo '```' >> $GITHUB_OUTPUT + echo "
" >> $GITHUB_OUTPUT + echo "${delimiter}" >> $GITHUB_OUTPUT + + # Publish Terraform Plan as task summary + - name: Publish Terraform Plan to Task Summary + env: + SUMMARY: ${{ steps.tf-plan-string.outputs.summary }} + run: | + echo "$SUMMARY" >> $GITHUB_STEP_SUMMARY + + # If this is a PR post the changes + - name: Push Terraform Output to PR + if: github.ref != 'refs/heads/main' + uses: actions/github-script@v6 + env: + SUMMARY: "${{ steps.tf-plan-string.outputs.summary }}" + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const body = `${process.env.SUMMARY}`; + github.rest.issues.createComment({ + issue_number: context.issue.number, + owner: context.repo.owner, + repo: context.repo.repo, + body: body + }) + + terraform-apply: + name: 'Terraform Apply' + if: github.ref == 'refs/heads/main' && needs.terraform-plan.outputs.tfplanExitCode == 2 + runs-on: ubuntu-latest + environment: production + needs: [terraform-plan] + + steps: + # Checkout the repository to the GitHub Actions runner + - name: Checkout + uses: actions/checkout@v3 + + # Install the latest version of Terraform CLI and configure the Terraform CLI configuration file with a Terraform Cloud user API token + - name: Setup Terraform + uses: hashicorp/setup-terraform@v2 + + # Initialize a new or existing Terraform working directory by creating initial files, loading any remote state, downloading modules, etc. + - name: Terraform Init + run: terraform init + + # Download saved plan from artifacts + - name: Download Terraform Plan + uses: actions/download-artifact@v3 + with: + name: tfplan + + # Terraform Apply + - name: Terraform Apply + run: terraform apply -auto-approve tfplan diff --git a/.github/workflows/tf-unit-tests.yml b/.github/workflows/tf-unit-tests.yml new file mode 100644 index 0000000..6ed4605 --- /dev/null +++ b/.github/workflows/tf-unit-tests.yml @@ -0,0 +1,45 @@ +name: 'Terraform Unit Tests' + +on: + push: + +jobs: + terraform-unit-tests: + name: 'Terraform Unit Tests' + runs-on: ubuntu-latest + + steps: + # Checkout the repository to the GitHub Actions runner + - name: Checkout + uses: actions/checkout@v3 + + # Install the latest version of Terraform CLI and configure the Terraform CLI configuration file with a Terraform Cloud user API token + - name: Setup Terraform + uses: hashicorp/setup-terraform@v2 + + # Initialize a new or existing Terraform working directory by creating initial files, loading any remote state, downloading modules, etc. + - name: Terraform Init + run: terraform init -backend=false + + # Validate terraform files + - name: Terraform Validate + run: terraform validate + + # Checks that all Terraform configuration files adhere to a canonical format + - name: Terraform Format + run: terraform fmt -check -recursive + + # Perform a security scan of the terraform code using checkov + - name: Run Checkov action + id: checkov + uses: bridgecrewio/checkov-action@master + with: + framework: terraform + + # Upload results to GitHub Advanced Security + - name: Upload SARIF file + if: success() || failure() + uses: github/codeql-action/upload-sarif@v2 + with: + sarif_file: results.sarif + category: checkov diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d6315c7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,442 @@ +##### Windows +# Windows thumbnail cache files +Thumbs.db +Thumbs.db:encryptable +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +##### Linux +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +##### MacOS +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +##### Backup +*.bak +*.gho +*.ori +*.orig +*.tmp + +##### GPG +secring.* + +##### Dropbox +# Dropbox settings and caches +.dropbox +.dropbox.attr +.dropbox.cache + +##### SynopsysVCS +# Waveform formats +*.vcd +*.vpd +*.evcd +*.fsdb + +# Default name of the simulation executable. A different name can be +# specified with this switch (the associated daidir database name is +# also taken from here): -o / +simv + +# Generated for Verilog and VHDL top configs +simv.daidir/ +simv.db.dir/ + +# Infrastructure necessary to co-simulate SystemC models with +# Verilog/VHDL models. An alternate directory may be specified with this +# switch: -Mdir= +csrc/ + +# Log file - the following switch allows to specify the file that will be +# used to write all messages from simulation: -l +*.log + +# Coverage results (generated with urg) and database location. The +# following switch can also be used: urg -dir .vdb +simv.vdb/ +urgReport/ + +# DVE and UCLI related files. +DVEfiles/ +ucli.key + +# When the design is elaborated for DirectC, the following file is created +# with declarations for C/C++ functions. +vc_hdrs.h + +##### SVN +.svn/ + +##### Mercurial +.hg/ +.hgignore +.hgsigs +.hgsub +.hgsubstate +.hgtags + +##### Bazaar +.bzr/ +.bzrignore + +##### CVS +/CVS/* +**/CVS/* +.cvsignore +*/.cvsignore + +##### TortoiseGit +# Project-level settings +/.tgitconfig + +##### PuTTY +# Private key +*.ppk + +##### Vim +# Swap +[._]*.s[a-v][a-z] +!*.svg # comment out if you don't need vector files +[._]*.sw[a-p] +[._]s[a-rt-v][a-z] +[._]ss[a-gi-z] +[._]sw[a-p] + +# Session +Session.vim +Sessionx.vim + +# Temporary +.netrwhist +*~ +# Auto-generated tag files +tags +# Persistent undo +[._]*.un~ + +##### Emacs +# -*- mode: gitignore; -*- +*~ +\#*\# +/.emacs.desktop +/.emacs.desktop.lock +*.elc +auto-save-list +tramp +.\#* + +# Org-mode +.org-id-locations +*_archive + +# flymake-mode +*_flymake.* + +# eshell files +/eshell/history +/eshell/lastdir + +# elpa packages +/elpa/ + +# reftex files +*.rel + +# AUCTeX auto folder +/auto/ + +# cask packages +.cask/ +dist/ + +# Flycheck +flycheck_*.el + +# server auth directory +/server/ + +# projectiles files +.projectile + +# directory configuration +.dir-locals.el + +# network security +/network-security.data + +##### SublimeText +# Cache files for Sublime Text +*.tmlanguage.cache +*.tmPreferences.cache +*.stTheme.cache + +# Workspace files are user-specific +*.sublime-workspace + +# Project files should be checked into the repository, unless a significant +# proportion of contributors will probably not be using Sublime Text +# *.sublime-project + +# SFTP configuration file +sftp-config.json +sftp-config-alt*.json + +# Package control specific files +Package Control.last-run +Package Control.ca-list +Package Control.ca-bundle +Package Control.system-ca-bundle +Package Control.cache/ +Package Control.ca-certs/ +Package Control.merged-ca-bundle +Package Control.user-ca-bundle +oscrypto-ca-bundle.crt +bh_unicode_properties.cache + +# Sublime-github package stores a github token in this file +# https://packagecontrol.io/packages/sublime-github +GitHub.sublime-settings + +##### Notepad++ +# Notepad++ backups # +*.bak + +##### TextMate +*.tmproj +*.tmproject +tmtags + +##### VisualStudioCode +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace + +# Local History for Visual Studio Code +.history/ + +##### NetBeans +**/nbproject/private/ +**/nbproject/Makefile-*.mk +**/nbproject/Package-*.bash +build/ +nbbuild/ +dist/ +nbdist/ +.nb-gradle/ + +##### JetBrains +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea + + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +##### Eclipse +.metadata +bin/ +tmp/ +*.tmp +*.bak +*.swp +*~.nib +local.properties +.settings/ +.loadpath +.recommenders + +# External tool builders +.externalToolBuilders/ + +# Locally stored "Eclipse launch configurations" +*.launch + +# PyDev specific (Python IDE for Eclipse) +*.pydevproject + +# CDT-specific (C/C++ Development Tooling) +.cproject + +# CDT- autotools +.autotools + +# Java annotation processor (APT) +.factorypath + +# PDT-specific (PHP Development Tools) +.buildpath + +# sbteclipse plugin +.target + +# Tern plugin +.tern-project + +# TeXlipse plugin +.texlipse + +# STS (Spring Tool Suite) +.springBeans + +# Code Recommenders +.recommenders/ + +# Annotation Processing +.apt_generated/ +.apt_generated_test/ + +# Scala IDE specific (Scala & Java development for Eclipse) +.cache-main +.scala_dependencies +.worksheet + +# Uncomment this line if you wish to ignore the project description file. +# Typically, this file would be tracked if it contains build/dependency configurations: +#.project + +##### Dreamweaver +# DW Dreamweaver added files +_notes +_compareTemp +configs/ +dwsync.xml +dw_php_codehinting.config +*.mno + +##### CodeKit +# General CodeKit files to ignore +config.codekit +config.codekit3 +/min + +##### Gradle +.gradle +**/build/ +!src/**/build/ + +# Ignore Gradle GUI config +gradle-app.setting + +# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored) +!gradle-wrapper.jar + +# Cache of project +.gradletasknamecache + +# # Work around https://youtrack.jetbrains.com/issue/IDEA-116898 +# gradle/wrapper/gradle-wrapper.properties + +##### Composer +composer.phar +/vendor/ + +# Commit your application's lock file https://getcomposer.org/doc/01-basic-usage.md#commit-your-composer-lock-file-to-version-control +# You may choose to ignore a library lock file http://getcomposer.org/doc/02-libraries.md#lock-file +composer.lock + +##### PHP CodeSniffer +# gitignore for the PHP Codesniffer framework +# website: https://github.com/squizlabs/PHP_CodeSniffer +# +# Recommended template: PHP.gitignore + +/wpcs/* + +##### SASS +.sass-cache/ +*.css.map +*.sass.map +*.scss.map \ No newline at end of file diff --git a/main.tf b/main.tf new file mode 100644 index 0000000..22ae8df --- /dev/null +++ b/main.tf @@ -0,0 +1,28 @@ +terraform { + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = ">= 3.7.0" + } + } + + # Update this block with the location of your terraform state file + backend "azurerm" { + resource_group_name = "rg-terraform-github-actions-state" + storage_account_name = "terraformgithubactions" + container_name = "tfstate" + key = "terraform.tfstate" + use_oidc = true + } +} + +provider "azurerm" { + features {} + use_oidc = true +} + +# Define any Azure resources to be created here. A simple resource group is shown here as a minimal example. +resource "azurerm_resource_group" "rg-aks" { + name = var.resource_group_name + location = var.location +} diff --git a/terraform.tfvars b/terraform.tfvars new file mode 100644 index 0000000..6440d63 --- /dev/null +++ b/terraform.tfvars @@ -0,0 +1,3 @@ +# Sample values +resource_group_name = "rg-terraform-github-actions" +location = "eastus" diff --git a/variables.tf b/variables.tf new file mode 100644 index 0000000..6b68db1 --- /dev/null +++ b/variables.tf @@ -0,0 +1,2 @@ +variable "resource_group_name" {} +variable "location" {} From d7422ee3aed1531932d9902b1e1cd6b2e7f48d92 Mon Sep 17 00:00:00 2001 From: Mathis Kappeler Date: Mon, 18 Dec 2023 16:57:56 +0100 Subject: [PATCH 2/5] test --- .github/workflows/tf-unit-tests.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/tf-unit-tests.yml b/.github/workflows/tf-unit-tests.yml index 6ed4605..2014e7f 100644 --- a/.github/workflows/tf-unit-tests.yml +++ b/.github/workflows/tf-unit-tests.yml @@ -3,6 +3,11 @@ name: 'Terraform Unit Tests' on: push: +permissions: + actions: read + contents: read + security-events: write + jobs: terraform-unit-tests: name: 'Terraform Unit Tests' From d832384550ea30b98c1d9c91aab54437fce52704 Mon Sep 17 00:00:00 2001 From: Mathis Kappeler Date: Tue, 19 Dec 2023 09:33:01 +0100 Subject: [PATCH 3/5] test --- README.md | 7 ++++++- main.tf | 8 ++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 656a54a..b87f340 100644 --- a/README.md +++ b/README.md @@ -1 +1,6 @@ -# meganeura \ No newline at end of file +# Meganeura + + +## Terraform on Azure using Github Actions + +https://github.com/Azure-Samples/terraform-github-actions diff --git a/main.tf b/main.tf index 22ae8df..18b3e9e 100644 --- a/main.tf +++ b/main.tf @@ -8,10 +8,10 @@ terraform { # Update this block with the location of your terraform state file backend "azurerm" { - resource_group_name = "rg-terraform-github-actions-state" - storage_account_name = "terraformgithubactions" - container_name = "tfstate" - key = "terraform.tfstate" + resource_group_name = "meganeura-tfstate" + storage_account_name = "meganeuratfstate" + container_name = "meganeura-tfstate" + key = "prod.terraform.tfstate" use_oidc = true } } From c0e39c7e36c70ea5cce63a603ae8cedf0fd51de3 Mon Sep 17 00:00:00 2001 From: Mathis Kappeler Date: Tue, 19 Dec 2023 10:33:10 +0100 Subject: [PATCH 4/5] test --- .github/CODE_OF_CONDUCT.md | 9 -- .github/dependabot.yml | 11 -- .github/workflows/terraform.yml | 48 ++++++++ .github/workflows/tf-drift.yml | 174 ---------------------------- .github/workflows/tf-plan-apply.yml | 146 ----------------------- .github/workflows/tf-unit-tests.yml | 50 -------- README.md | 1 + main.tf | 30 ++--- terraform.tfvars | 3 - variables.tf | 2 - 10 files changed, 60 insertions(+), 414 deletions(-) delete mode 100644 .github/CODE_OF_CONDUCT.md delete mode 100644 .github/dependabot.yml create mode 100644 .github/workflows/terraform.yml delete mode 100644 .github/workflows/tf-drift.yml delete mode 100644 .github/workflows/tf-plan-apply.yml delete mode 100644 .github/workflows/tf-unit-tests.yml delete mode 100644 terraform.tfvars delete mode 100644 variables.tf diff --git a/.github/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md deleted file mode 100644 index f9ba8cf..0000000 --- a/.github/CODE_OF_CONDUCT.md +++ /dev/null @@ -1,9 +0,0 @@ -# Microsoft Open Source Code of Conduct - -This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). - -Resources: - -- [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/) -- [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) -- Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns diff --git a/.github/dependabot.yml b/.github/dependabot.yml deleted file mode 100644 index 7602182..0000000 --- a/.github/dependabot.yml +++ /dev/null @@ -1,11 +0,0 @@ -# To get started with Dependabot version updates, you'll need to specify which -# package ecosystems to update and where the package manifests are located. -# Please see the documentation for all configuration options: -# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates - -version: 2 -updates: - - package-ecosystem: "terraform" # See documentation for possible values - directory: "/" # Location of package manifests - schedule: - interval: "weekly" diff --git a/.github/workflows/terraform.yml b/.github/workflows/terraform.yml new file mode 100644 index 0000000..174739e --- /dev/null +++ b/.github/workflows/terraform.yml @@ -0,0 +1,48 @@ +name: 'Terraform' + +on: + push: + branches: + - main + pull_request: + workflow_dispatch: + +permissions: + contents: read + +jobs: + terraform: + name: 'Terraform' + env: + ARM_CLIENT_ID: ${{ secrets.AZURE_CLIENT_ID }} + ARM_CLIENT_SECRET: ${{ secrets.AZURE_CLIENT_SECRET }} + ARM_SUBSCRIPTION_ID: ${{ secrets.AZURE_SUBSCRIPTION_ID }} + ARM_TENANT_ID: ${{ secrets.AZURE_TENANT_ID }} + runs-on: ubuntu-latest + environment: production + # Use the Bash shell regardless of whether the GitHub Actions runner is ubuntu-latest, macos-latest, or windows-latest + defaults: + run: + shell: bash + steps: + # Checkout the repository to the GitHub Actions runner + - name: Checkout + uses: actions/checkout@v3 + + # Install the latest version of Terraform CLI and configure the Terraform CLI configuration file with a Terraform Cloud user API token + - name: Setup Terraform + uses: hashicorp/setup-terraform@v2 + with: + cli_config_credentials_token: ${{ secrets.TF_API_TOKEN }} + + # Initialize a new or existing Terraform working directory by creating initial files, loading any remote state, downloading modules, etc. + - name: Terraform Init + run: terraform init + + # Generates an execution plan for Terraform + - name: Terraform Plan + run: terraform plan -input=false + + # Apply Terraform changes + - name: Terraform Apply + run: terraform apply -auto-approve -input=false diff --git a/.github/workflows/tf-drift.yml b/.github/workflows/tf-drift.yml deleted file mode 100644 index a92b2d3..0000000 --- a/.github/workflows/tf-drift.yml +++ /dev/null @@ -1,174 +0,0 @@ -name: 'Terraform Configuration Drift Detection' - -on: - workflow_dispatch: - schedule: - - cron: '41 3 * * *' # runs nightly at 3:41 am - -#Special permissions required for OIDC authentication -permissions: - id-token: write - contents: read - issues: write - -#These environment variables are used by the terraform azure provider to setup OIDD authenticate. -env: - ARM_CLIENT_ID: "${{ secrets.AZURE_CLIENT_ID }}" - ARM_SUBSCRIPTION_ID: "${{ secrets.AZURE_SUBSCRIPTION_ID }}" - ARM_TENANT_ID: "${{ secrets.AZURE_TENANT_ID }}" - -jobs: - terraform-plan: - name: 'Terraform Plan' - runs-on: ubuntu-latest - env: - #this is needed since we are running terraform with read-only permissions - ARM_SKIP_PROVIDER_REGISTRATION: true - outputs: - tfplanExitCode: ${{ steps.tf-plan.outputs.exitcode }} - - steps: - # Checkout the repository to the GitHub Actions runner - - name: Checkout - uses: actions/checkout@v3 - - # Install the latest version of the Terraform CLI - - name: Setup Terraform - uses: hashicorp/setup-terraform@v2 - with: - terraform_wrapper: false - - # Initialize a new or existing Terraform working directory by creating initial files, loading any remote state, downloading modules, etc. - - name: Terraform Init - run: terraform init - - # Generates an execution plan for Terraform - # An exit code of 0 indicated no changes, 1 a terraform failure, 2 there are pending changes. - - name: Terraform Plan - id: tf-plan - run: | - export exitcode=0 - terraform plan -detailed-exitcode -no-color -out tfplan || export exitcode=$? - - echo "exitcode=$exitcode" >> $GITHUB_OUTPUT - - if [ $exitcode -eq 1 ]; then - echo Terraform Plan Failed! - exit 1 - else - exit 0 - fi - - # Save plan to artifacts - - name: Publish Terraform Plan - uses: actions/upload-artifact@v3 - with: - name: tfplan - path: tfplan - - # Create string output of Terraform Plan - - name: Create String Output - id: tf-plan-string - run: | - TERRAFORM_PLAN=$(terraform show -no-color tfplan) - - delimiter="$(openssl rand -hex 8)" - echo "summary<<${delimiter}" >> $GITHUB_OUTPUT - echo "## Terraform Plan Output" >> $GITHUB_OUTPUT - echo "
Click to expand" >> $GITHUB_OUTPUT - echo "" >> $GITHUB_OUTPUT - echo '```terraform' >> $GITHUB_OUTPUT - echo "$TERRAFORM_PLAN" >> $GITHUB_OUTPUT - echo '```' >> $GITHUB_OUTPUT - echo "
" >> $GITHUB_OUTPUT - echo "${delimiter}" >> $GITHUB_OUTPUT - - # Publish Terraform Plan as task summary - - name: Publish Terraform Plan to Task Summary - env: - SUMMARY: ${{ steps.tf-plan-string.outputs.summary }} - run: | - echo "$SUMMARY" >> $GITHUB_STEP_SUMMARY - - # If changes are detected, create a new issue - - name: Publish Drift Report - if: steps.tf-plan.outputs.exitcode == 2 - uses: actions/github-script@v6 - env: - SUMMARY: "${{ steps.tf-plan-string.outputs.summary }}" - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - const body = `${process.env.SUMMARY}`; - const title = 'Terraform Configuration Drift Detected'; - const creator = 'github-actions[bot]' - - // Look to see if there is an existing drift issue - const issues = await github.rest.issues.listForRepo({ - owner: context.repo.owner, - repo: context.repo.repo, - state: 'open', - creator: creator, - title: title - }) - - if( issues.data.length > 0 ) { - // We assume there shouldn't be more than 1 open issue, since we update any issue we find - const issue = issues.data[0] - - if ( issue.body == body ) { - console.log('Drift Detected: Found matching issue with duplicate content') - } else { - console.log('Drift Detected: Found matching issue, updating body') - github.rest.issues.update({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: issue.number, - body: body - }) - } - } else { - console.log('Drift Detected: Creating new issue') - - github.rest.issues.create({ - owner: context.repo.owner, - repo: context.repo.repo, - title: title, - body: body - }) - } - - # If changes aren't detected, close any open drift issues - - name: Publish Drift Report - if: steps.tf-plan.outputs.exitcode == 0 - uses: actions/github-script@v6 - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - const title = 'Terraform Configuration Drift Detected'; - const creator = 'github-actions[bot]' - - // Look to see if there is an existing drift issue - const issues = await github.rest.issues.listForRepo({ - owner: context.repo.owner, - repo: context.repo.repo, - state: 'open', - creator: creator, - title: title - }) - - if( issues.data.length > 0 ) { - const issue = issues.data[0] - - github.rest.issues.update({ - owner: context.repo.owner, - repo: context.repo.repo, - issue_number: issue.number, - state: 'closed' - }) - } - - # Mark the workflow as failed if drift detected - - name: Error on Failure - if: steps.tf-plan.outputs.exitcode == 2 - run: exit 1 diff --git a/.github/workflows/tf-plan-apply.yml b/.github/workflows/tf-plan-apply.yml deleted file mode 100644 index 1e97900..0000000 --- a/.github/workflows/tf-plan-apply.yml +++ /dev/null @@ -1,146 +0,0 @@ -name: 'Terraform Plan/Apply' - -on: - push: - branches: - - main - pull_request: - branches: - - main - -#Special permissions required for OIDC authentication -permissions: - id-token: write - contents: read - pull-requests: write - -#These environment variables are used by the terraform azure provider to setup OIDD authenticate. -env: - ARM_CLIENT_ID: "${{ secrets.AZURE_CLIENT_ID }}" - ARM_SUBSCRIPTION_ID: "${{ secrets.AZURE_SUBSCRIPTION_ID }}" - ARM_TENANT_ID: "${{ secrets.AZURE_TENANT_ID }}" - -jobs: - terraform-plan: - name: 'Terraform Plan' - runs-on: ubuntu-latest - env: - #this is needed since we are running terraform with read-only permissions - ARM_SKIP_PROVIDER_REGISTRATION: true - outputs: - tfplanExitCode: ${{ steps.tf-plan.outputs.exitcode }} - - steps: - # Checkout the repository to the GitHub Actions runner - - name: Checkout - uses: actions/checkout@v3 - - # Install the latest version of the Terraform CLI - - name: Setup Terraform - uses: hashicorp/setup-terraform@v2 - with: - terraform_wrapper: false - - # Initialize a new or existing Terraform working directory by creating initial files, loading any remote state, downloading modules, etc. - - name: Terraform Init - run: terraform init - - # Checks that all Terraform configuration files adhere to a canonical format - # Will fail the build if not - - name: Terraform Format - run: terraform fmt -check - - # Generates an execution plan for Terraform - # An exit code of 0 indicated no changes, 1 a terraform failure, 2 there are pending changes. - - name: Terraform Plan - id: tf-plan - run: | - export exitcode=0 - terraform plan -detailed-exitcode -no-color -out tfplan || export exitcode=$? - - echo "exitcode=$exitcode" >> $GITHUB_OUTPUT - - if [ $exitcode -eq 1 ]; then - echo Terraform Plan Failed! - exit 1 - else - exit 0 - fi - - # Save plan to artifacts - - name: Publish Terraform Plan - uses: actions/upload-artifact@v3 - with: - name: tfplan - path: tfplan - - # Create string output of Terraform Plan - - name: Create String Output - id: tf-plan-string - run: | - TERRAFORM_PLAN=$(terraform show -no-color tfplan) - - delimiter="$(openssl rand -hex 8)" - echo "summary<<${delimiter}" >> $GITHUB_OUTPUT - echo "## Terraform Plan Output" >> $GITHUB_OUTPUT - echo "
Click to expand" >> $GITHUB_OUTPUT - echo "" >> $GITHUB_OUTPUT - echo '```terraform' >> $GITHUB_OUTPUT - echo "$TERRAFORM_PLAN" >> $GITHUB_OUTPUT - echo '```' >> $GITHUB_OUTPUT - echo "
" >> $GITHUB_OUTPUT - echo "${delimiter}" >> $GITHUB_OUTPUT - - # Publish Terraform Plan as task summary - - name: Publish Terraform Plan to Task Summary - env: - SUMMARY: ${{ steps.tf-plan-string.outputs.summary }} - run: | - echo "$SUMMARY" >> $GITHUB_STEP_SUMMARY - - # If this is a PR post the changes - - name: Push Terraform Output to PR - if: github.ref != 'refs/heads/main' - uses: actions/github-script@v6 - env: - SUMMARY: "${{ steps.tf-plan-string.outputs.summary }}" - with: - github-token: ${{ secrets.GITHUB_TOKEN }} - script: | - const body = `${process.env.SUMMARY}`; - github.rest.issues.createComment({ - issue_number: context.issue.number, - owner: context.repo.owner, - repo: context.repo.repo, - body: body - }) - - terraform-apply: - name: 'Terraform Apply' - if: github.ref == 'refs/heads/main' && needs.terraform-plan.outputs.tfplanExitCode == 2 - runs-on: ubuntu-latest - environment: production - needs: [terraform-plan] - - steps: - # Checkout the repository to the GitHub Actions runner - - name: Checkout - uses: actions/checkout@v3 - - # Install the latest version of Terraform CLI and configure the Terraform CLI configuration file with a Terraform Cloud user API token - - name: Setup Terraform - uses: hashicorp/setup-terraform@v2 - - # Initialize a new or existing Terraform working directory by creating initial files, loading any remote state, downloading modules, etc. - - name: Terraform Init - run: terraform init - - # Download saved plan from artifacts - - name: Download Terraform Plan - uses: actions/download-artifact@v3 - with: - name: tfplan - - # Terraform Apply - - name: Terraform Apply - run: terraform apply -auto-approve tfplan diff --git a/.github/workflows/tf-unit-tests.yml b/.github/workflows/tf-unit-tests.yml deleted file mode 100644 index 2014e7f..0000000 --- a/.github/workflows/tf-unit-tests.yml +++ /dev/null @@ -1,50 +0,0 @@ -name: 'Terraform Unit Tests' - -on: - push: - -permissions: - actions: read - contents: read - security-events: write - -jobs: - terraform-unit-tests: - name: 'Terraform Unit Tests' - runs-on: ubuntu-latest - - steps: - # Checkout the repository to the GitHub Actions runner - - name: Checkout - uses: actions/checkout@v3 - - # Install the latest version of Terraform CLI and configure the Terraform CLI configuration file with a Terraform Cloud user API token - - name: Setup Terraform - uses: hashicorp/setup-terraform@v2 - - # Initialize a new or existing Terraform working directory by creating initial files, loading any remote state, downloading modules, etc. - - name: Terraform Init - run: terraform init -backend=false - - # Validate terraform files - - name: Terraform Validate - run: terraform validate - - # Checks that all Terraform configuration files adhere to a canonical format - - name: Terraform Format - run: terraform fmt -check -recursive - - # Perform a security scan of the terraform code using checkov - - name: Run Checkov action - id: checkov - uses: bridgecrewio/checkov-action@master - with: - framework: terraform - - # Upload results to GitHub Advanced Security - - name: Upload SARIF file - if: success() || failure() - uses: github/codeql-action/upload-sarif@v2 - with: - sarif_file: results.sarif - category: checkov diff --git a/README.md b/README.md index b87f340..0a7a934 100644 --- a/README.md +++ b/README.md @@ -4,3 +4,4 @@ ## Terraform on Azure using Github Actions https://github.com/Azure-Samples/terraform-github-actions +https://gmusumeci.medium.com/deploying-terraform-in-azure-using-github-actions-step-by-step-bf8804b17711 \ No newline at end of file diff --git a/main.tf b/main.tf index 18b3e9e..3317123 100644 --- a/main.tf +++ b/main.tf @@ -1,28 +1,20 @@ +# Define Terraform provider terraform { + required_version = ">= 1.3" + backend "azurerm" { + resource_group_name = "mn-tfstate-rg" + storage_account_name = "mntfstate" + container_name = "tfstate" + key = "prod.terraform.tfstate" + } required_providers { azurerm = { + version = "~>3.2" source = "hashicorp/azurerm" - version = ">= 3.7.0" } } - - # Update this block with the location of your terraform state file - backend "azurerm" { - resource_group_name = "meganeura-tfstate" - storage_account_name = "meganeuratfstate" - container_name = "meganeura-tfstate" - key = "prod.terraform.tfstate" - use_oidc = true - } } - +# Configure the Azure provider provider "azurerm" { features {} - use_oidc = true -} - -# Define any Azure resources to be created here. A simple resource group is shown here as a minimal example. -resource "azurerm_resource_group" "rg-aks" { - name = var.resource_group_name - location = var.location -} +} \ No newline at end of file diff --git a/terraform.tfvars b/terraform.tfvars deleted file mode 100644 index 6440d63..0000000 --- a/terraform.tfvars +++ /dev/null @@ -1,3 +0,0 @@ -# Sample values -resource_group_name = "rg-terraform-github-actions" -location = "eastus" diff --git a/variables.tf b/variables.tf deleted file mode 100644 index 6b68db1..0000000 --- a/variables.tf +++ /dev/null @@ -1,2 +0,0 @@ -variable "resource_group_name" {} -variable "location" {} From a953fd07dd710ad415f56f8f234f7f8458fe6232 Mon Sep 17 00:00:00 2001 From: Mathis Kappeler Date: Tue, 19 Dec 2023 10:42:09 +0100 Subject: [PATCH 5/5] test --- .github/workflows/terraform.yml | 45 +++++++++++++++++---------------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/.github/workflows/terraform.yml b/.github/workflows/terraform.yml index 174739e..c586d3e 100644 --- a/.github/workflows/terraform.yml +++ b/.github/workflows/terraform.yml @@ -24,25 +24,26 @@ jobs: defaults: run: shell: bash - steps: - # Checkout the repository to the GitHub Actions runner - - name: Checkout - uses: actions/checkout@v3 - - # Install the latest version of Terraform CLI and configure the Terraform CLI configuration file with a Terraform Cloud user API token - - name: Setup Terraform - uses: hashicorp/setup-terraform@v2 - with: - cli_config_credentials_token: ${{ secrets.TF_API_TOKEN }} - - # Initialize a new or existing Terraform working directory by creating initial files, loading any remote state, downloading modules, etc. - - name: Terraform Init - run: terraform init - - # Generates an execution plan for Terraform - - name: Terraform Plan - run: terraform plan -input=false - - # Apply Terraform changes - - name: Terraform Apply - run: terraform apply -auto-approve -input=false + + steps: + # Checkout the repository to the GitHub Actions runner + - name: Checkout + uses: actions/checkout@v3 + + # Install the latest version of the Terraform CLI + - name: Setup Terraform + uses: hashicorp/setup-terraform@v2 + with: + terraform_wrapper: false + + # Initialize a new or existing Terraform working directory by creating initial files, loading any remote state, downloading modules, etc. + - name: Terraform Init + run: terraform init + + # Generates an execution plan for Terraform + - name: Terraform Plan + run: terraform plan -input=false + + # Apply Terraform changes + - name: Terraform Apply + run: terraform apply -auto-approve -input=false