|
| 1 | +--- |
| 2 | +title: "With Terragrunt" |
| 3 | +--- |
| 4 | + |
| 5 | +In this tutorial, you will set up Digger to automate Terragrunt pull requests using Github Actions |
| 6 | + |
| 7 | +# Prerequisites |
| 8 | + |
| 9 | +- A GitHub repository with valid Terragrunt code |
| 10 | +- Your cloud provider credentials: |
| 11 | + - For AWS: [Hashicorp's AWS tutorial](https://developer.hashicorp.com/terraform/tutorials/aws-get-started/aws-build) |
| 12 | + - For GCP: [Hashicorp's GCP tutorial](https://developer.hashicorp.com/terraform/tutorials/gcp-get-started/google-cloud-platform-build) |
| 13 | + |
| 14 | +# Step 1: create your Digger account |
| 15 | + |
| 16 | +Head to [ui.digger.dev](https://ui.digger.dev) and sign up using your preferred method. |
| 17 | + |
| 18 | +You should see an empty dashboard after you sign up. |
| 19 | + |
| 20 | +# Step 2: install the Digger GitHub App |
| 21 | + |
| 22 | +Install the Digger [GitHub App](https://github.com/apps/digger-pro/installations/select_target) into your repository. |
| 23 | + |
| 24 | +<Note> |
| 25 | +Digger GitHub App does not need access to your cloud account, it just starts jobs in your CI. All sensitive data stays in your CI job. |
| 26 | + |
| 27 | +You can also [self-host Digger orchestrator](/ce/self-host/deploy-docker) with a private GiHub app and issue your own token |
| 28 | + |
| 29 | +</Note> |
| 30 | + |
| 31 | +# Step 3: Create Action Secrets with cloud credentials |
| 32 | + |
| 33 | +In GitHub repository settings, go to Secrets and Variables - Actions. Create the following secrets: |
| 34 | + |
| 35 | +<Tabs> |
| 36 | + <Tab title="AWS"> |
| 37 | + - `AWS_ACCESS_KEY_ID` |
| 38 | + - `AWS_SECRET_ACCESS_KEY` |
| 39 | + |
| 40 | + You can also [use OIDC](/ce/cloud-providers/authenticating-with-oidc-on-aws) for AWS authentication. |
| 41 | + </Tab> |
| 42 | + <Tab title="GCP"> |
| 43 | + - `GCP_CREDENTIALS` - contents of your GCP Service Account Key json file |
| 44 | + |
| 45 | + You can also [use OIDC](/gcp/federated-oidc-access/) for GCP authentication. |
| 46 | + </Tab> |
| 47 | +</Tabs> |
| 48 | + |
| 49 | +# Step 4: Create digger.yml |
| 50 | + |
| 51 | +Terragrunt projects can be configured in two ways: |
| 52 | + |
| 53 | +## Option A: Individual projects (for smaller setups) |
| 54 | + |
| 55 | +If you have a few Terragrunt modules, you can list them individually: |
| 56 | + |
| 57 | +```yaml |
| 58 | +projects: |
| 59 | +- name: dev |
| 60 | + dir: dev |
| 61 | + terragrunt: true |
| 62 | +- name: prod |
| 63 | + dir: prod |
| 64 | + terragrunt: true |
| 65 | +``` |
| 66 | +
|
| 67 | +## Option B: Generated projects (recommended for larger setups) |
| 68 | +
|
| 69 | +For Terragrunt monorepos with many modules, use the blocks syntax to automatically generate projects: |
| 70 | +
|
| 71 | +```yaml |
| 72 | +generate_projects: |
| 73 | + blocks: |
| 74 | + - block_name: dev |
| 75 | + terragrunt: true |
| 76 | + root_dir: "dev/" |
| 77 | + workflow: default |
| 78 | + - block_name: staging |
| 79 | + terragrunt: true |
| 80 | + root_dir: "staging/" |
| 81 | + workflow: default |
| 82 | + - block_name: prod |
| 83 | + terragrunt: true |
| 84 | + root_dir: "prod/" |
| 85 | + workflow: default |
| 86 | + |
| 87 | +workflows: |
| 88 | + default: |
| 89 | + plan: |
| 90 | + steps: |
| 91 | + - init |
| 92 | + - plan |
| 93 | + apply: |
| 94 | + steps: |
| 95 | + - init |
| 96 | + - apply |
| 97 | +``` |
| 98 | +
|
| 99 | +This approach automatically discovers all Terragrunt modules under each directory and creates projects for them. Digger will also handle dependencies between modules. |
| 100 | +
|
| 101 | +<Note> |
| 102 | +For more advanced configurations and performance optimization for large monorepos, see [Using Terragrunt](/ce/howto/using-terragrunt) and [Generate Projects](/ce/howto/generate-projects#blocks-syntax-with-terragrunt). |
| 103 | +</Note> |
| 104 | +
|
| 105 | +# Step 5: Create Github Actions workflow file |
| 106 | +
|
| 107 | +Place it at `.github/workflows/digger_workflow.yml` (name is important!) |
| 108 | + |
| 109 | +<Tabs> |
| 110 | + <Tab title="AWS"> |
| 111 | + ```yaml |
| 112 | + name: Digger Workflow |
| 113 | +
|
| 114 | + on: |
| 115 | + workflow_dispatch: |
| 116 | + inputs: |
| 117 | + spec: |
| 118 | + required: true |
| 119 | + run_name: |
| 120 | + required: false |
| 121 | +
|
| 122 | + run-name: '${{inputs.run_name}}' |
| 123 | +
|
| 124 | + jobs: |
| 125 | + digger-job: |
| 126 | + runs-on: ubuntu-latest |
| 127 | + permissions: |
| 128 | + contents: write # required to merge PRs |
| 129 | + actions: write # required for plan persistence |
| 130 | + id-token: write # required for workload-identity-federation |
| 131 | + pull-requests: write # required to post PR comments |
| 132 | + issues: read # required to check if PR number is an issue or not |
| 133 | + statuses: write # required to validate combined PR status |
| 134 | +
|
| 135 | + steps: |
| 136 | + - uses: actions/checkout@v4 |
| 137 | + - name: ${{ fromJSON(github.event.inputs.spec).job_id }} |
| 138 | + run: echo "job id ${{ fromJSON(github.event.inputs.spec).job_id }}" |
| 139 | + - uses: diggerhq/digger@vLatest |
| 140 | + with: |
| 141 | + digger-spec: ${{ inputs.spec }} |
| 142 | + setup-aws: true |
| 143 | + setup-terragrunt: true |
| 144 | + terragrunt-version: 0.44.1 |
| 145 | + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} |
| 146 | + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} |
| 147 | + env: |
| 148 | + GITHUB_CONTEXT: ${{ toJson(github) }} |
| 149 | + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
| 150 | + ``` |
| 151 | + </Tab> |
| 152 | + <Tab title="GCP"> |
| 153 | + ```yaml |
| 154 | + name: Digger |
| 155 | +
|
| 156 | + on: |
| 157 | + workflow_dispatch: |
| 158 | + inputs: |
| 159 | + spec: |
| 160 | + required: true |
| 161 | + run_name: |
| 162 | + required: false |
| 163 | +
|
| 164 | + run-name: '${{inputs.run_name}}' |
| 165 | +
|
| 166 | + jobs: |
| 167 | + digger-job: |
| 168 | + name: Digger |
| 169 | + runs-on: ubuntu-latest |
| 170 | + permissions: |
| 171 | + contents: write # required to merge PRs |
| 172 | + actions: write # required for plan persistence |
| 173 | + id-token: write # required for workload-identity-federation |
| 174 | + pull-requests: write # required to post PR comments |
| 175 | + issues: read # required to check if PR number is an issue or not |
| 176 | + statuses: write # required to validate combined PR status |
| 177 | + steps: |
| 178 | + - uses: actions/checkout@v4 |
| 179 | + - name: ${{ fromJSON(github.event.inputs.spec).job_id }} |
| 180 | + run: echo "job id ${{ fromJSON(github.event.inputs.spec).job_id }}" |
| 181 | + - id: 'auth' |
| 182 | + uses: 'google-github-actions/auth@v1' |
| 183 | + with: |
| 184 | + credentials_json: '${{ secrets.GCP_CREDENTIALS }}' |
| 185 | + create_credentials_file: true |
| 186 | + - name: 'Set up Cloud SDK' |
| 187 | + uses: 'google-github-actions/setup-gcloud@v1' |
| 188 | + - name: 'Use gcloud CLI' |
| 189 | + run: 'gcloud info' |
| 190 | + - name: digger run |
| 191 | + uses: diggerhq/digger@vLatest |
| 192 | + with: |
| 193 | + digger-spec: ${{ inputs.spec }} |
| 194 | + setup-aws: false |
| 195 | + setup-terragrunt: true |
| 196 | + terragrunt-version: 0.44.1 |
| 197 | + env: |
| 198 | + GITHUB_CONTEXT: ${{ toJson(github) }} |
| 199 | + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
| 200 | + ``` |
| 201 | + |
| 202 | + This workflow includes additional steps for GCP: |
| 203 | + - Authenticate into GCP using Google's official [Auth action](https://github.com/google-github-actions/auth). Note the `create_credentials_file: true` option; without it, subsequent steps that rely on [Application Default Credentials](https://cloud.google.com/docs/authentication/provide-credentials-adc) will not work. |
| 204 | + - Set up Google Cloud SDK for use in the subsequent steps via Google's official [Setup-gcloud action](https://github.com/google-github-actions/setup-gcloud) |
| 205 | + - Verify that GCP is configured correctly by running `gcloud info` |
| 206 | + </Tab> |
| 207 | +</Tabs> |
| 208 | + |
| 209 | +<Note> |
| 210 | +Notice that we use `setup-terragrunt: true` instead of `setup-terraform`. Terragrunt will handle the Terraform binary installation internally. |
| 211 | +</Note> |
| 212 | + |
| 213 | +# Step 6: Create a PR to verify that it works |
| 214 | + |
| 215 | +Terragrunt will run an existing plan against your code. |
| 216 | + |
| 217 | +Make any change to your Terragrunt code e.g. add a blank line. An action run should start (you can see log output in Actions). After some time you should see output of Terragrunt Plan added as a comment to your PR. |
| 218 | + |
| 219 | +Then you can add a comment like `digger apply` and shortly after apply output will be added as comment too. |
| 220 | + |
| 221 | +# Demo repositories |
| 222 | + |
| 223 | +- [Individual projects demo](https://github.com/diggerhq/demo-terragrunt-gcp) |
| 224 | +- [Generated projects demo](https://github.com/diggerhq/test-terragrunt-racecondition) |
| 225 | + |
| 226 | +# Important notes |
| 227 | + |
| 228 | +## SOPS integration |
| 229 | + |
| 230 | +If you use `sops_decrypt_file` in your `terragrunt.hcl`, you need to handle the case when Digger generates projects in the backend. Use the `DIGGER_GENERATE_PROJECT` environment variable: |
| 231 | + |
| 232 | +```hcl |
| 233 | +locals { |
| 234 | + secrets = get_env("DIGGER_GENERATE_PROJECT", "false") == "true" ? {} : yamldecode(sops_decrypt_file("secrets.yaml")) |
| 235 | +} |
| 236 | +``` |
| 237 | + |
| 238 | +This prevents SOPS decryption errors during project generation. |
| 239 | + |
| 240 | +## Performance optimization |
| 241 | + |
| 242 | +For very large Terragrunt monorepos, consider: |
| 243 | +- Using the blocks syntax to segment your repository |
| 244 | +- Implementing [config caching](/ce/howto/generate-projects#caching-digger-config) for faster PR processing |
| 245 | +- Organizing modules by environment or provider to minimize traversal time |
0 commit comments