├── providers.tf
├── main.tf
├── README.md
├── policies
├── s3-bucket-state.json
├── role-trusted-entity.json
└── ssm-permisions.json
├── .gitignore
└── github-action.yml
/providers.tf:
--------------------------------------------------------------------------------
1 | terraform {
2 | backend "s3" {}
3 | }
--------------------------------------------------------------------------------
/main.tf:
--------------------------------------------------------------------------------
1 | resource "aws_ssm_parameter" "foo" {
2 | name = "foo"
3 | type = "String"
4 | value = "barr"
5 | }
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # github-oidc-terraform
2 |
3 | You need to set the file github-action.yml inside this directory:
4 |
5 | ```bash
6 | .github/workflows/
7 | ```
8 |
9 | Blog post : [https://cloudscalr.com/deploy-to-aws-with-terraform-within-a-github-action/](https://cloudscalr.com/deploy-to-aws-with-terraform-within-a-github-action/)
10 |
11 | Youtube video : [https://www.youtube.com/watch?v=GowFk_5Rx_I](https://www.youtube.com/watch?v=GowFk_5Rx_I)
12 |
--------------------------------------------------------------------------------
/policies/s3-bucket-state.json:
--------------------------------------------------------------------------------
1 | {
2 | "Version": "2012-10-17",
3 | "Statement": [
4 | {
5 | "Effect": "Allow",
6 | "Action": [
7 | "s3:PutObject",
8 | "s3:GetObject",
9 | "s3:ListBucket"
10 | ],
11 | "Resource": [
12 | "arn:aws:s3:::YOUR_BUCKET/*",
13 | "arn:aws:s3:::YOUR_BUCKET"
14 | ]
15 | }
16 | ]
17 | }
18 |
--------------------------------------------------------------------------------
/policies/role-trusted-entity.json:
--------------------------------------------------------------------------------
1 | {
2 | "Version": "2008-10-17",
3 | "Statement": [
4 | {
5 | "Effect": "Allow",
6 | "Principal": {
7 | "Federated": "arn:aws:iam::YOUR_ACCOUNT_NUMBER:oidc-provider/token.actions.githubusercontent.com"
8 | },
9 | "Action": "sts:AssumeRoleWithWebIdentity",
10 | "Condition": {
11 | "StringLike": {
12 | "token.actions.githubusercontent.com:sub": "repo:YOUR_GITHUB_USERNAME/YOUR_REPO_NAME:*"
13 | }
14 | }
15 | }
16 | ]
17 | }
18 |
--------------------------------------------------------------------------------
/policies/ssm-permisions.json:
--------------------------------------------------------------------------------
1 | {
2 | "Version": "2012-10-17",
3 | "Statement": [
4 | {
5 | "Sid": "VisualEditor0",
6 | "Effect": "Allow",
7 | "Action": [
8 | "ssm:PutParameter",
9 | "ssm:LabelParameterVersion",
10 | "ssm:DeleteParameter",
11 | "ssm:UnlabelParameterVersion",
12 | "ssm:DescribeParameters",
13 | "ssm:GetParameterHistory",
14 | "ssm:ListTagsForResource",
15 | "ssm:GetParametersByPath",
16 | "ssm:GetParameters",
17 | "ssm:GetParameter",
18 | "ssm:DeleteParameters"
19 | ],
20 | "Resource": "*"
21 | }
22 | ]
23 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Local .terraform directories
2 | **/.terraform/*
3 |
4 | # .tfstate files
5 | *.tfstate
6 | *.tfstate.*
7 |
8 | # Crash log files
9 | crash.log
10 | crash.*.log
11 |
12 | # Exclude all .tfvars files, which are likely to contain sensitive data, such as
13 | # password, private keys, and other secrets. These should not be part of version
14 | # control as they are data points which are potentially sensitive and subject
15 | # to change depending on the environment.
16 | *.tfvars
17 | *.tfvars.json
18 |
19 | # Ignore override files as they are usually used to override resources locally and so
20 | # are not checked in
21 | override.tf
22 | override.tf.json
23 | *_override.tf
24 | *_override.tf.json
25 |
26 | # Include override files you do wish to add to version control using negated pattern
27 | # !example_override.tf
28 |
29 | # Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan
30 | # example: *tfplan*
31 |
32 | # Ignore CLI configuration files
33 | .terraformrc
34 | terraform.rc
--------------------------------------------------------------------------------
/github-action.yml:
--------------------------------------------------------------------------------
1 | name: "Terraform action"
2 | on:
3 | push:
4 | branches:
5 | - main
6 | pull_request:
7 | permissions:
8 | id-token: write # This is required for aws oidc connection
9 | contents: read # This is required for actions/checkout
10 | pull-requests: write # This is required for gh bot to comment PR
11 | env:
12 | TF_LOG: INFO
13 | AWS_REGION: ${{ secrets.AWS_REGION }}
14 | jobs:
15 | deploy:
16 | runs-on: ubuntu-latest
17 | defaults:
18 | run:
19 | shell: bash
20 | working-directory: .
21 | steps:
22 | - name: Git checkout
23 | uses: actions/checkout@v3
24 |
25 | - name: Configure AWS credentials from AWS account
26 | uses: aws-actions/configure-aws-credentials@v1
27 | with:
28 | role-to-assume: ${{ secrets.AWS_ROLE }}
29 | aws-region: ${{ secrets.AWS_REGION }}
30 | role-session-name: GitHub-OIDC-TERRAFORM
31 |
32 | - name: Setup Terraform
33 | uses: hashicorp/setup-terraform@v2
34 | with:
35 | terraform_version: 1.2.5
36 |
37 | - name: Terraform fmt
38 | id: fmt
39 | run: terraform fmt -check
40 | continue-on-error: true
41 |
42 | - name: Terraform Init
43 | id: init
44 | env:
45 | AWS_BUCKET_NAME: ${{ secrets.AWS_BUCKET_NAME }}
46 | AWS_BUCKET_KEY_NAME: ${{ secrets.AWS_BUCKET_KEY_NAME }}
47 | run: terraform init -backend-config="bucket=${AWS_BUCKET_NAME}" -backend-config="key=${AWS_BUCKET_KEY_NAME}" -backend-config="region=${AWS_REGION}"
48 |
49 | - name: Terraform Validate
50 | id: validate
51 | run: terraform validate -no-color
52 |
53 | - name: Terraform Plan
54 | id: plan
55 | run: terraform plan -no-color
56 | if: github.event_name == 'pull_request'
57 | continue-on-error: true
58 |
59 | - uses: actions/github-script@v6
60 | if: github.event_name == 'pull_request'
61 | env:
62 | PLAN: "terraform\n${{ steps.plan.outputs.stdout }}"
63 | with:
64 | github-token: ${{ secrets.GITHUB_TOKEN }}
65 | script: |
66 | const output = `#### Terraform Format and Style 🖌\`${{ steps.fmt.outcome }}\`
67 | #### Terraform Initialization ⚙️\`${{ steps.init.outcome }}\`
68 | #### Terraform Validation 🤖\`${{ steps.validate.outcome }}\`
69 | Validation Output
70 |
71 | \`\`\`\n
72 | ${{ steps.validate.outputs.stdout }}
73 | \`\`\`
74 |
75 |
76 |
77 | #### Terraform Plan 📖\`${{ steps.plan.outcome }}\`
78 |
79 | Show Plan
80 |
81 | \`\`\`\n
82 | ${process.env.PLAN}
83 | \`\`\`
84 |
85 |
86 |
87 | *Pushed by: @${{ github.actor }}, Action: \`${{ github.event_name }}\`*`;
88 |
89 | github.rest.issues.createComment({
90 | issue_number: context.issue.number,
91 | owner: context.repo.owner,
92 | repo: context.repo.repo,
93 | body: output
94 | })
95 |
96 | - name: Terraform Plan Status
97 | if: steps.plan.outcome == 'failure'
98 | run: exit 1
99 |
100 | - name: Terraform Apply
101 | if: github.ref == 'refs/heads/main' && github.event_name == 'push'
102 | run: terraform apply -auto-approve -input=false
103 |
--------------------------------------------------------------------------------