diff --git a/.github/workflows/test_artifact_encrypted.yml b/.github/workflows/test_artifact_encrypted.yml new file mode 100644 index 0000000..3c150eb --- /dev/null +++ b/.github/workflows/test_artifact_encrypted.yml @@ -0,0 +1,41 @@ +name: Test Terraform State Artifact Encrypted +on: + workflow_dispatch: + push: + +jobs: + test_artifact_encrypted: + runs-on: ubuntu-latest + name: Test Terraform State Artifact Encrypted + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + - name: Download Encrypted Artifact & Decrypt Artifact + uses: badgerhobbs/terraform-state@master + with: + encryption_key: ${{ secrets.encryption_key }} + operation: download + location: artifact + continue-on-error: true + + - name: Configure Terraform + uses: hashicorp/setup-terraform@v2 + + - name: Initialize Terraform + run: terraform init + + - name: Run Terraform Plan + run: | + terraform plan -var="run_id=${{ github.run_id }}" + + - name: Run Terraform Apply + run: | + terraform apply -auto-approve -var="run_id=${{ github.run_id }}" + + - name: Encrypt Artifact & Upload Encrypted Artifact + uses: badgerhobbs/terraform-state@master + with: + encryption_key: ${{ secrets.encryption_key }} + operation: upload + location: artifact diff --git a/.github/workflows/test_artifact_raw.yml b/.github/workflows/test_artifact_raw.yml new file mode 100644 index 0000000..ba50295 --- /dev/null +++ b/.github/workflows/test_artifact_raw.yml @@ -0,0 +1,39 @@ +name: Test Terraform State Artifact Raw +on: + workflow_dispatch: + push: + +jobs: + test_artifact_raw: + runs-on: ubuntu-latest + name: Test Terraform State Artifact Raw + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + - name: Download Raw Artifact + uses: badgerhobbs/terraform-state@master + with: + operation: upload + location: artifact + continue-on-error: true + + - name: Configure Terraform + uses: hashicorp/setup-terraform@v2 + + - name: Initialize Terraform + run: terraform init + + - name: Run Terraform Plan + run: | + terraform plan -var="run_id=${{ github.run_id }}" + + - name: Run Terraform Apply + run: | + terraform apply -auto-approve -var="run_id=${{ github.run_id }}" + + - name: Upload Raw Artifact + uses: badgerhobbs/terraform-state@master + with: + operation: upload + location: artifact diff --git a/.github/workflows/test_repository_file_encrypted.yml b/.github/workflows/test_repository_file_encrypted.yml new file mode 100644 index 0000000..609e1e7 --- /dev/null +++ b/.github/workflows/test_repository_file_encrypted.yml @@ -0,0 +1,41 @@ +name: Test Terraform State Repository File Encrypted +on: + workflow_dispatch: + push: + +jobs: + test_repository_file_encrypted: + runs-on: ubuntu-latest + name: Test Terraform State Repository File Encrypted + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + - name: Decrypt Repository File + uses: badgerhobbs/terraform-state@master + with: + encryption_key: ${{ secrets.encryption_key }} + operation: download + location: repository + continue-on-error: true + + - name: Configure Terraform + uses: hashicorp/setup-terraform@v2 + + - name: Initialize Terraform + run: terraform init + + - name: Run Terraform Plan + run: | + terraform plan -var="run_id=${{ github.run_id }}" + + - name: Run Terraform Apply + run: | + terraform apply -auto-approve -var="run_id=${{ github.run_id }}" + + - name: Encrypt and Commit Repository File + uses: badgerhobbs/terraform-state@master + with: + encryption_key: ${{ secrets.encryption_key }} + operation: upload + location: repository diff --git a/.github/workflows/test_repository_file_raw.yml b/.github/workflows/test_repository_file_raw.yml new file mode 100644 index 0000000..9da0e00 --- /dev/null +++ b/.github/workflows/test_repository_file_raw.yml @@ -0,0 +1,32 @@ +name: Test Terraform State Repository File Raw +on: + workflow_dispatch: + push: + +jobs: + test_repository_file_raw: + runs-on: ubuntu-latest + name: Test Terraform State Repository File Raw + steps: + - name: Checkout repository + uses: actions/checkout@v2 + + - name: Configure Terraform + uses: hashicorp/setup-terraform@v2 + + - name: Initialize Terraform + run: terraform init + + - name: Run Terraform Plan + run: | + terraform plan -var="run_id=${{ github.run_id }}" + + - name: Run Terraform Apply + run: | + terraform apply -auto-approve -var="run_id=${{ github.run_id }}" + + - name: Commit Repository File + uses: badgerhobbs/terraform-state@master + with: + operation: upload + location: repository diff --git a/action.yml b/action.yml new file mode 100644 index 0000000..eea976a --- /dev/null +++ b/action.yml @@ -0,0 +1,113 @@ +name: "terraform-state" +description: "Stores Terraform state file as encrypted artifact or repository file." +author: "Andrew Riggs" + +inputs: + encryption_key: + description: "AES-256 Encryption key used to encrypt/decrypt the Terraform state file." + required: false + default: "" + + operation: + description: "Specifies if the operation is to download or upload the Terraform state file. [Options: download/upload]" + required: true + + location: + description: "Specifies the storage location of the Terraform state file. [Options: repository/artifact]" + required: true + + directory: + description: "Directory of the Terraform state file." + required: false + default: "" + +runs: + using: "composite" + steps: + + # Raw Artifact + - name: Download Raw Artifact + if: "${{ inputs.location == 'artifact' && inputs.operation == 'download' && inputs.encryption_key == '' }}" + shell: bash + run: | + REPO="${{ github.repository }}" + ARTIFACT_URI="https://api.github.com/repos/$REPO/actions/artifacts" + TOKEN="${{ github.token }}" + RESPONSE=$(curl -H "Authorization: token $TOKEN" -s $ARTIFACT_URI | jq -r '.artifacts[]') + if [ "$RESPONSE" ] ; then + LATEST_ARTIFACT_URI=$(echo $RESPONSE | jq -r 'select(.name=="Raw Terraform State") | .url' | sort -r | head -n 1) + echo "Most recent artifact URI = $LATEST_ARTIFACT_URI" + if [ "$LATEST_ARTIFACT_URI" ] ; then + curl -L -H "Authorization: token $TOKEN" -o ${{ inputs.directory }}/terraform.tfstate.zip $LATEST_ARTIFACT_URI + unzip ${{ inputs.directory }}/terraform.tfstate.zip + fi + fi + + - name: Upload Raw Artifact + if: "${{ inputs.location == 'artifact' && inputs.operation == 'upload' && inputs.encryption_key == '' }}" + uses: actions/upload-artifact@v3 + with: + name: Raw Terraform State + path: "${{ inputs.directory }}/terraform.tfstate" + + # Encrypted Artifact + - name: Download Encrypted Artifact + if: "${{ inputs.location == 'artifact' && inputs.operation == 'download' && inputs.encryption_key != '' }}" + shell: bash + run: | + REPO="${{ github.repository }}" + ARTIFACT_URI="https://api.github.com/repos/$REPO/actions/artifacts" + TOKEN="${{ github.token }}" + RESPONSE=$(curl -H "Authorization: token $TOKEN" -s $ARTIFACT_URI | jq -r '.artifacts[]') + if [ "$RESPONSE" ] ; then + LATEST_ARTIFACT_URI=$(echo $RESPONSE | jq -r 'select(.name=="Encrypted Terraform State") | .url' | sort -r | head -n 1) + echo "Most recent artifact URI = $LATEST_ARTIFACT_URI" + if [ "$LATEST_ARTIFACT_URI" ] ; then + curl -L -H "Authorization: token $TOKEN" -o ${{ inputs.directory }}/terraform.tfstate.encrypted.zip $LATEST_ARTIFACT_URI + unzip ${{ inputs.directory }}/terraform.tfstate.encrypted.zip + fi + fi + + - name: Decrypt Artifact + if: "${{ inputs.location == 'artifact' && inputs.operation == 'download' && inputs.encryption_key != '' }}" + shell: bash + run: | + openssl enc -d -aes256 -in ${{ inputs.directory }}/terraform.tfstate.encrypted -out ${{ inputs.directory }}/terraform.tfstate -k ${{ inputs.encryption_key }} + + - name: Encrypt Artifact + if: "${{ inputs.location == 'artifact' && inputs.operation == 'upload' && inputs.encryption_key != '' }}" + shell: bash + run: | + openssl enc -e -aes256 -in ${{ inputs.directory }}/terraform.tfstate -out ${{ inputs.directory }}/terraform.tfstate.encrypted -k ${{ inputs.encryption_key }} + + - name: Upload Encrypted Artifact + if: "${{ inputs.location == 'artifact' && inputs.operation == 'upload' && inputs.encryption_key != '' }}" + uses: actions/upload-artifact@v3 + with: + name: Encrypted Terraform State + path: "${{ inputs.directory }}/terraform.tfstate.encrypted" + + # Raw Repository File + - name: Commit Repository File + if: "${{ inputs.location == 'repository' && inputs.operation == 'upload' && inputs.encryption_key == '' }}" + shell: bash + run: | + git add ${{ inputs.directory }}/terraform.tfstate + git commit -m "Update Encrypted Terraform State" + git push + + # Encrypted Repository File + - name: Decrypt Repository File + if: "${{ inputs.location == 'repository' && inputs.operation == 'download' && inputs.encryption_key != '' }}" + shell: bash + run: | + openssl enc -d -aes256 -in ${{ inputs.directory }}/terraform.tfstate.encrypted -out ${{ inputs.directory }}/terraform.tfstate -k ${{ inputs.encryption_key }} + + - name: Encrypt and Commit Repository File + if: "${{ inputs.location == 'repository' && inputs.operation == 'upload' && inputs.encryption_key != '' }}" + shell: bash + run: | + openssl enc -e -aes256 -in ${{ inputs.directory }}/terraform.tfstate -out ${{ inputs.directory }}/terraform.tfstate.encrypted -k ${{ inputs.encryption_key }} + git add ${{ inputs.directory }}/terraform.tfstate.encrypted + git commit -m "Update Encrypted Terraform State" + git push diff --git a/main.tf b/main.tf new file mode 100644 index 0000000..bca7886 --- /dev/null +++ b/main.tf @@ -0,0 +1,19 @@ +terraform { + required_providers { + random = { + source = "hashicorp/random" + version = "3.1.0" + } + } +} + +resource "random_id" "random" { + keepers = { + random_id = "${var.run_id}" + } + byte_length = 8 +} + +variable "run_id" { + type = string +}