Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Terraform workflow #55

Merged
merged 20 commits into from
Aug 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
5405749
feat: added terraform workflow file
VishwajitNagulkar Jul 24, 2023
d97efec
feat: updated Readme doc
VishwajitNagulkar Jul 24, 2023
83c87c9
format: updated workflow name
VishwajitNagulkar Jul 24, 2023
60f663b
feat: updated readme documentation
VishwajitNagulkar Jul 24, 2023
94ea534
Update terraform_workflow.md
VishwajitNagulkar Jul 24, 2023
b800edc
Update terraform_workflow.md
VishwajitNagulkar Jul 24, 2023
c85f8a5
feat: updated Readme with respect to terraform workflow
VishwajitNagulkar Jul 24, 2023
f5ee12e
Update README.md
VishwajitNagulkar Jul 24, 2023
3dacda3
feat: updated terraform plan command
VishwajitNagulkar Jul 28, 2023
d4e4771
feat: added input for terraform version
VishwajitNagulkar Jul 31, 2023
14c6aca
Merge branch 'master' into internal_357
anmolnagpal Jul 31, 2023
61de796
feat: updated readme doc
VishwajitNagulkar Jul 31, 2023
e42d682
feat: added terraform version as a input
VishwajitNagulkar Jul 31, 2023
8605a82
feat: update plan, init and format steps
VishwajitNagulkar Aug 1, 2023
0820f1b
feat: updated environments which is suitable for digtalocean provider
VishwajitNagulkar Aug 2, 2023
7c3b91b
format: updated names of cloud provider
VishwajitNagulkar Aug 2, 2023
f6f65e9
feat: added example for for azure, digitalocean, gcp
VishwajitNagulkar Aug 2, 2023
64b0fe2
feat: added aws OIDC role for auth.
VishwajitNagulkar Aug 3, 2023
3fbe81e
feat: added input for aws role
VishwajitNagulkar Aug 3, 2023
310f3fd
feat: added step which support aws keys as well as aws role
VishwajitNagulkar Aug 3, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
219 changes: 219 additions & 0 deletions .github/workflows/terraform_workflow.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
run-name: 'Terraform workflow'
on:
workflow_call:
inputs:
working_directory:
required: true
type: string
description: 'Root directory of the terraform where all resources exist.'
provider:
required: true
type: string
default: aws
description: 'Cloud provider to run the workflow. e.g. azurerm, aws, gcp or digitalocean'
aws_region:
required: false
type: string
default: us-east-2
description: 'AWS region of terraform deployment.'
gcp_region:
required: false
type: string
description: 'GCP region of terraform deployment.'
var_file:
required: false
type: string
description: 'Terraform var file directory. e.g. vars/dev.tfvars'
destroy:
type: string
default: false
description: 'you want to destroy infra or not'
approvers:
required: false
type: string
description: 'Approvals list to approve apply or destroy'
terraform_version:
type: string
default: 1.3.6
description: 'Required erraform version '
timeout:
required: false
type: number
default: 10
description: 'Timeout for approval step'
secrets:
AZURE_CREDENTIALS:
required: false
description: 'Azure Credentials to install Azure in github runner.'
AWS_ACCESS_KEY_ID:
required: false
description: 'AWS Access Key ID to install AWS CLI.'
BUILD_ROLE:
required: false
description: 'AWS OIDC role for aws authentication.'
AWS_SECRET_ACCESS_KEY:
required: false
description: 'AWS Secret access key to install AWS CLI'
AWS_SESSION_TOKEN:
required: false
description: 'AWS Session Token to install AWS CLI'
GCP_SA_KEY:
required: false
description: 'GCP service account Secret access key to install GCP CLI'
PROJECT_ID:
required: false
description: 'GCP Secret access key to install GCP CLI'
DIGITALOCEAN_ACCESS_TOKEN:
required: false
description: 'Digitalocean access Token to install Digitalocean CLI'
SPACES_ACCESS_KEY_ID:
required: false
description: 'Spaces access key ID for digitalocean if required'
SPACES_SECRET_ACCESS_KEY:
required: false
description: 'Spaces secret access key for digitalocean if required'

jobs:
terraform-workflow:
runs-on: ubuntu-latest
env:
ARM_SKIP_PROVIDER_REGISTRATION: true
DIGITALOCEAN_TOKEN: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }}
SPACES_ACCESS_KEY_ID: ${{ secrets.SPACES_ACCESS_KEY_ID }}
SPACES_SECRET_ACCESS_KEY: ${{ secrets.SPACES_SECRET_ACCESS_KEY }}
outputs:
tfplanExitCode: ${{ steps.tf-plan.outputs.exitcode }}

steps:
- name: Checkout
uses: actions/checkout@v3

- name: Install AWS CLI
if: ${{ inputs.provider == 'aws' }}
uses: aws-actions/configure-aws-credentials@v2
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-session-token: ${{ secrets.AWS_SESSION_TOKEN }}
role-to-assume: ${{ secrets.BUILD_ROLE }}
aws-region: ${{ inputs.aws_region }}
role-duration-seconds: 900
role-skip-session-tagging: true

- name: Install Azure CLI
if: ${{ inputs.provider == 'azurerm' }}
uses: azure/login@v1
with:
creds: ${{ secrets.AZURE_CREDENTIALS }}

- name: Install GCP CLI
if: ${{ inputs.provider == 'gcp' }}
uses: google-github-actions/auth@v0
with:
service_account_key: ${{ secrets.GCP_SA_KEY }}
project_id: ${{ secrets.PROJECT_ID }}
region: ${{ inputs.gcp_region }}

- name: Install doctl
if: ${{ inputs.provider == 'digitalocean' }}
uses: digitalocean/action-doctl@v2
with:
token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }}

- name: Set up Terraform
uses: hashicorp/setup-terraform@v2
with:
terraform_version: ${{ inputs.terraform_version }}

- name: 'Terraform Format'
if: ${{ inputs.destroy != 'true' }}
id: fmt
uses: 'dflook/terraform-fmt-check@v1'
with:
actions_subcommand: 'fmt'
path: ${{ inputs.working_directory }}

- name: terraform init
run: |
cd ${{ inputs.working_directory }}
terraform init

- name: 'Terraform validate'
if: ${{ inputs.destroy != 'true' }}
id: validate
uses: dflook/terraform-validate@v1
with:
tf_actions_working_dir: ${{ inputs.working_directory }}

- name: Terraform Plan
id: tf-plan
run: |
export exitcode=0
cd ${{ inputs.working_directory }}
if [ "${{ inputs.destroy }}" = "true" ]; then
if [ -n "${{ inputs.var_file }}" ]; then
terraform plan -destroy -out tfplan --var-file=${{ inputs.var_file }}
else
terraform plan -destroy -out tfplan
fi
else
if [ -n "${{ inputs.var_file }}" ]; then
terraform plan -out tfplan --var-file=${{ inputs.var_file }}
else
terraform plan -out tfplan
fi
fi

- name: Publish Terraform Plan
uses: actions/upload-artifact@v3
with:
name: tfplan
path: ${{ inputs.working_directory }}/tfplan

- name: Create String Output
id: tf-plan-string
run: |
cd ${{ inputs.working_directory }}
TERRAFORM_PLAN=$(terraform show -no-color tfplan)
delimiter="$(openssl rand -hex 8)"
echo "summary<<${delimiter}" >> $GITHUB_OUTPUT
echo "## Terraform Plan Output" >> $GITHUB_OUTPUT
echo "<details><summary>Click to expand</summary>" >> $GITHUB_OUTPUT
echo "" >> $GITHUB_OUTPUT
echo '```terraform' >> $GITHUB_OUTPUT
echo "$TERRAFORM_PLAN" >> $GITHUB_OUTPUT
echo '```' >> $GITHUB_OUTPUT
echo "</details>" >> $GITHUB_OUTPUT
echo "${delimiter}" >> $GITHUB_OUTPUT

- name: "Accept plan or deny"
uses: trstringer/manual-approval@v1
timeout-minutes: ${{ inputs.timeout }}
with:
secret: ${{ github.TOKEN }}
approvers: ${{ inputs.approvers }}
issue-title: "Terraform Plan for Infrastructure Update"
issue-body: ${{ steps.tf-plan-string.outputs.summary }}

- name: terraform apply
if: ${{ inputs.destroy != 'true' }}
run: |
if [ -n "${{ inputs.var_file }}" ]; then
cd ${{ inputs.working_directory }}
terraform apply -var-file="${{ inputs.var_file }}" -auto-approve
else
cd ${{ inputs.working_directory }}
terraform apply -auto-approve
fi

- name: Terraform destroy
if: ${{ inputs.destroy == 'true' }}
id: destroy
run: |
if [ -n "${{ inputs.var_file }}" ]; then
cd ${{ inputs.working_directory }}
terraform destroy -var-file="${{ inputs.var_file }}" -auto-approve
else
cd ${{ inputs.working_directory }}
terraform destroy -auto-approve
fi
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ Above example is just a simple example to call workflow from github shared workf
6. [Terraform Lint Workflow](https://github.com/clouddrove/github-shared-workflows/blob/master/docs/terraform-lint.md)
7. [Terraform Checks Workflow](https://github.com/clouddrove/github-shared-workflows/blob/master/docs/terraform-checks.md)
7. [Checkov Workflow](https://github.com/clouddrove/github-shared-workflows/blob/master/docs/checkov.md)
8. [Terraform Workflow](https://github.com/clouddrove/github-shared-workflows/blob/master/docs/terraform_workflow.md)

## Feedback
If you come accross a bug or have any feedback, please log it in our [issue tracker](https://github.com/clouddrove/github-shared-workflows/issues), or feel free to drop us an email at [[email protected]](mailto:[email protected]).
Expand Down
104 changes: 104 additions & 0 deletions docs/terraform_workflow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
## [Terraform Workflow](https://github.com/clouddrove/github-shared-workflows/blob/master/.github/workflows/terraform_workflow.yml)

This workflow is used to apply and destroy terraform infra using GitHub Actions. It utilizes the workflows defined in `.github/workflows/terraform_workflow.yml`

#### Usage
This workflow generates an issue before the apply or destroy step with a required plan in it. If we comment "yes", "lgtm" the workflow will proceed to the next step. However, if we comment "deny," the workflow will be canceled.

#### Example of a Terraform workflow for a AWS cloud provider
```yaml
name: terraform workflow
permissions: write-all
on:
push:
branches: [ master ]
pull_request:
workflow_dispatch:
jobs:
prod:
uses: clouddrove/github-shared-workflows/.github/workflows/terraform_workflow.yml@master
with:
provider: # aws
working_directory: # Specify terraform code directory in repo
var_file: # name of tfvar file e.g "variable.tfvar"
aws_region: # specify region eg. us-east-2
approvers: # Assignee name for approve apply or destroy step
terraform_version: # Specify terraform version e.g 1.3.6
destroy: # If the value is set to true, the workflow proceeds to the destroy step. However, the default value is false
secrets:
AWS_ACCESS_KEY_ID: # Specify AWS Access key ID
AWS_SECRET_ACCESS_KEY: # Specify AWS Secret Access key ID
AWS_SESSION_TOKEN: # Specify Session ID

```

#### Example of a Terraform workflow for a Azure cloud provider
```yaml
name: terraform workflow
permissions: write-all
on:
push:
branches: [ master ]
pull_request:
workflow_dispatch:
jobs:
prod:
uses: clouddrove/github-shared-workflows/.github/workflows/terraform_workflow.yml@master
with:
provider: # azurerm
working_directory: # Specify terraform code directory in repo
var_file: # Name of tfvar file e.g "variable.tfvar"
approvers: # Assignee name for approve apply or destroy step
terraform_version: # Specify terraform version e.g 1.3.6
destroy: # If the value is set to true, the workflow proceeds to the destroy step. However, the default value is false
secrets:
AZURE_CREDENTIALS: # Specify Azure credentilas
```

#### Example of a Terraform workflow for a Digitalocean cloud provider
```yaml
name: terraform workflow
permissions: write-all
on:
push:
branches: [ master ]
pull_request:
workflow_dispatch:
jobs:
prod:
uses: clouddrove/github-shared-workflows/.github/workflows/terraform_workflow.yml@master
with:
provider: # digitalocean
working_directory: # Specify terraform code directory in repo
var_file: # Name of tfvar file e.g "variable.tfvar"
approvers: # Assignee name for approve apply or destroy step
terraform_version: # Specify terraform version e.g 1.3.6
destroy: # If the value is set to true, the workflow proceeds to the destroy step. However, the default value is false
secrets:
DIGITALOCEAN_TOKEN: # Digitalocean token
SPACES_ACCESS_KEY_ID: # Provide spaces access key id if required
SPACES_SECRET_ACCESS_KEY: # Provide spaces secret access key if required
```

#### Example of a Terraform workflow for a GCP cloud provider
```yaml
name: terraform workflow
permissions: write-all
on:
push:
branches: [ master ]
pull_request:
workflow_dispatch:
jobs:
prod:
uses: clouddrove/github-shared-workflows/.github/workflows/terraform_workflow.yml@master
with:
provider: # gcp
working_directory: # Specify terraform code directory in repo
var_file: # Name of tfvar file e.g "variable.tfvar"
approvers: # Assignee name for approve apply or destroy step
terraform_version: # Specify terraform version e.g 1.3.6
destroy: # If the value is set to true, the workflow proceeds to the destroy step. However, the default value is false
secrets:
GCP_SA_KEY: # GCP service account Secret access key
```