DEV Community

Cover image for How Terraform Auto-Updates GitHub Secrets After Deploy — And Why It Matters
Ervin Wallin
Ervin Wallin

Posted on

How Terraform Auto-Updates GitHub Secrets After Deploy — And Why It Matters

Most CI/CD guides stop at "Terraform provisions your infrastructure." But there's a gap nobody talks about: what happens to the values Terraform just created?

After terraform apply, you have a fresh LAMBDA_URL and an SNS_TOPIC_ARN. Your GitHub Actions pipeline needs both to run smoke tests and send alerts. The typical solution? Copy-paste them manually into GitHub Secrets. Every. Single. Time.

This is exactly what I eliminated in my v2.1 project — and it took the deployment from "almost automated" to genuinely zero manual steps.


The Problem: The Last Manual Step

Here's the scenario. You run Terraform, it creates:

  • A Lambda Function URL (dynamically assigned by AWS)
  • An SNS topic ARN (unique per account/region)

Your CI/CD pipeline references both of these as GitHub Secrets. But Terraform just created them — so the secrets are stale or missing until someone updates them manually.

This is a surprisingly common pattern in otherwise well-automated setups. The infrastructure is IaC, the pipeline is automated, but there's always one human in the loop doing:

Settings → Secrets → Update → Paste value → Save
Enter fullscreen mode Exit fullscreen mode

Not great.


The Solution: Terraform Writes Back to GitHub

The GitHub Terraform Provider lets you manage GitHub resources — including repository secrets — as Terraform resources.

Here's the core idea:

provider "github" {
  owner = "your-github-username"
  app_auth {
    id              = var.github_app_id
    installation_id = var.github_app_installation_id
    pem_file        = file(var.github_app_pem_file_path)
  }
}

resource "github_actions_secret" "lambda_url" {
  repository      = "your-app-repo"
  secret_name     = "LAMBDA_URL"
  plaintext_value = aws_lambda_function_url.main.function_url
}

resource "github_actions_secret" "sns_topic_arn" {
  repository      = "your-app-repo"
  secret_name     = "SNS_TOPIC_ARN"
  plaintext_value = aws_sns_topic.alerts.arn
}
Enter fullscreen mode Exit fullscreen mode

After terraform apply, both secrets are updated automatically. No human involved.


Why GitHub App Auth (Not a Personal Token)

You might be tempted to use a personal access token for the GitHub provider. Don't.

A GitHub App gives you:

  • Scoped permissions — only what it needs (secrets write on specific repos)
  • No personal token rotation — the App uses a short-lived JWT, not a long-lived secret
  • Audit trail — actions are attributed to the App, not your personal account

To set it up, you need three values in your terraform.tfvars (never commit this file):

github_app_id              = "12345"
github_app_installation_id = "67890"
github_app_pem_file_path   = "./github-app-private-key.pem"
Enter fullscreen mode Exit fullscreen mode

These stay local. The GitHub Provider uses them to generate short-lived tokens at apply time.


The Full Zero-Manual-Step Loop

Once this is in place, the complete flow looks like this:

  1. terraform apply runs
  2. AWS creates Lambda Function URL + SNS Topic (dynamic values)
  3. Terraform reads those output values
  4. GitHub Provider writes them directly to GitHub Secrets
  5. GitHub Actions pipeline picks them up on the next run — no stale values, no manual update

The pipeline can then safely run a smoke test against the freshly deployed Lambda URL, and the CloudWatch alarm already knows where to send alerts via SNS.

This closes what I call the infrastructure feedback loop: deployed infrastructure automatically feeds its runtime configuration back into the CI/CD system.


What This Looks Like End-to-End

In my project (v2.1 of an agnostic serverless Lambda core), the full CI/CD flow after this change is:

  • Push to main
  • GitHub Actions checks out the app repo, runs quality gates (flake8, bandit, pytest)
  • Docker build → push to ECR
  • Lambda function updated with the new container image
  • Smart smoke test: polls the Lambda URL for 40 seconds, checks the VERSION env var
  • If anything fails, CloudWatch alarm fires → SNS → email

Zero manual steps. Zero stale secrets. The only local requirement is having the GitHub App credentials for the initial terraform apply.


Key Takeaways

  • The GitHub Terraform Provider is underused — most teams still manage repo secrets by hand
  • GitHub App auth is the right choice over personal tokens for automation
  • Closing the infrastructure feedback loop (infra → CI/CD config) is the difference between "almost automated" and actually automated
  • This pattern works for any dynamic value Terraform creates: API Gateway URLs, RDS endpoints, CloudFront distributions

Resources


Ervin Wallin — Cloud & Platform Engineer. Building reproducible, secure, serverless systems.

AWS Certified Developer · HashiCorp Terraform Associate

Top comments (0)