Skip to content

libops/terraform-linux-packages

Repository files navigation

terraform-linux-packages

Terraform for a dedicated Google Cloud project that serves Linux packages from a public GCS bucket behind HTTPS, with GitHub Actions write access via Workload Identity Federation.

GitHub Access Model

Only the repositories listed in github_repositories receive:

  • LIBOPS_PACKAGES_GCLOUD_OIDC_POOL
  • LIBOPS_PACKAGES_GCLOUD_PROJECT
  • LIBOPS_PACKAGES_GCLOUD_REGION
  • LIBOPS_PACKAGES_GSA
  • LIBOPS_PACKAGES_GCS_BUCKET
  • LIBOPS_PACKAGES_PACKAGE_REPO_URL
  • LIBOPS_PACKAGES_APTLY_GPG_KEY_ID
  • LIBOPS_PACKAGES_APTLY_GPG_PRIVATE_KEY_SECRET
  • LIBOPS_PACKAGES_APTLY_GPG_PASSPHRASE_SECRET

If github_actors is non-empty, the Workload Identity provider also restricts access to those actors. That check happens in the provider attribute_condition, so both repository and actor must match.

Usage

  1. Export credentials for both providers:
export GOOGLE_APPLICATION_CREDENTIALS=/path/to/admin-creds.json
export GITHUB_TOKEN=ghp_xxx
  1. Review and copy the example variables:
cp terraform.tfvars.example terraform.tfvars
  1. Initialize and apply:
terraform init
terraform plan
terraform apply
  1. Add the Aptly GPG material out of band after Terraform creates the Secret Manager containers:
make create-aptly-gpg-key
make sync-aptly-gpg-key-id

make create-aptly-gpg-key prompts for the passphrase without echoing it and saves the revocation certificate under .out/gpg/.

  1. Delegate the reported DNS name servers for the package subdomain, for example packages.libops.io, from the parent DNS zone.

Publishing

This repo includes a local publishing path that mirrors the shared GitHub Actions workflow.

Prerequisites:

  • gh authenticated for the source GitHub repository
  • docker
  • gcloud authenticated for Secret Manager and GCS on the host

By default the local targets use the published tooling image ghcr.io/libops/terraform-linux-packages:main. To rebuild that image locally instead, run:

make package-tools-image-local

Example:

make package GITHUB_REPOSITORY=libops/sitectl PACKAGE_NAME=sitectl RELEASE_VERSION=v1.2.3

That target will:

  • download the .deb and .rpm release assets with gh
  • pull the published Linux tooling image if needed
  • fetch the GPG key material from Secret Manager inside the container
  • rebuild the Debian and RPM repository metadata inside the container
  • sync the result to the package bucket prefix for that package

On macOS, this avoids needing native installs of aptly or createrepo_c.

To print or sync the signing key ID from Secret Manager:

make print-aptly-gpg-key-id
make sync-aptly-gpg-key-id

Notes

  • The managed SSL certificate will stay in provisioning until the delegated package subdomain resolves to the created load balancer IP.
  • The bucket is public so apt and other package managers can fetch package metadata and artifacts without authentication.
  • This stack grants the GitHub service account bucket-level roles/storage.objectAdmin, which is enough for syncing package repositories into the bucket.
  • Terraform creates the Secret Manager secret containers, but it does not write the private key or passphrase into Terraform state.

libops setup

Below are the commands ran to get packages.libops.io setup using this repo

publish the latest version for our utils

terraform init
terraform apply
make create-aptly-gpg-key GCLOUD_PROJECT=libops-linux-packages
make sync-aptly-gpg-key-id
terraform apply
make package \
  GITHUB_REPOSITORY=libops/sitectl \
  PACKAGE_NAME=sitectl \
  RELEASE_VERSION=v0.10.1
make package \
  GITHUB_REPOSITORY=libops/sitectl-drupal \
  PACKAGE_NAME=sitectl-drupal \
  RELEASE_VERSION=v0.0.4
make package \
  GITHUB_REPOSITORY=libops/sitectl-isle \
  PACKAGE_NAME=sitectl-isle \
  RELEASE_VERSION=v0.6.1

Requirements

Name Version
terraform >= 1.2.4
github 6.11.1
google 7.24.0

Providers

Name Version
github.libops 6.11.1
google 7.24.0

Modules

No modules.

Resources

Name Type
github_actions_variable.aptly_gpg_key_id resource
github_actions_variable.aptly_gpg_passphrase_secret resource
github_actions_variable.aptly_gpg_private_key_secret resource
github_actions_variable.bucket resource
github_actions_variable.gsa resource
github_actions_variable.oidc resource
github_actions_variable.package_url resource
github_actions_variable.project resource
github_actions_variable.region resource
google_compute_backend_bucket.packages resource
google_compute_global_address.packages resource
google_compute_global_forwarding_rule.packages_https resource
google_compute_managed_ssl_certificate.packages resource
google_compute_target_https_proxy.packages resource
google_compute_url_map.packages resource
google_dns_managed_zone.packages resource
google_dns_record_set.packages_a resource
google_iam_workload_identity_pool.pool resource
google_iam_workload_identity_pool_provider.github resource
google_project.project resource
google_project_service.service resource
google_secret_manager_secret.aptly_passphrase resource
google_secret_manager_secret.aptly_private_key resource
google_secret_manager_secret_iam_member.github_aptly_passphrase_accessor resource
google_secret_manager_secret_iam_member.github_aptly_private_key_accessor resource
google_service_account.github resource
google_service_account_iam_member.oidc_user resource
google_storage_bucket.packages resource
google_storage_bucket_iam_member.github_writer resource
google_storage_bucket_iam_member.public_read resource
github_repository.repo data source

Inputs

Name Description Type Default Required
aptly_gpg_key_id GPG key ID Aptly uses to sign the published repository. string "" no
aptly_gpg_passphrase_secret_id Secret Manager secret ID that stores the Aptly GPG key passphrase. string "aptly-gpg-passphrase" no
aptly_gpg_private_key_secret_id Secret Manager secret ID that stores the armored Aptly private key. string "aptly-gpg-private-key" no
billing_account Google Cloud billing account ID. string n/a yes
bucket_location Bucket location. string "US" no
bucket_name Name of the public package bucket. string "libops-linux-packages" no
dns_zone_dns_name DNS suffix managed by the zone, with trailing dot. string "packages.libops.io." no
dns_zone_name Cloud DNS managed zone name. string "packages-libops-io" no
github_actors Optional GitHub actors allowed to use the provider. Leave empty to allow any actor from the approved repositories. set(string) [] no
github_owner GitHub organization that owns the repositories allowed to publish packages. string "libops" no
github_repositories Full GitHub repository names allowed to impersonate the publishing service account. set(string)
[
"libops/sitectl",
"libops/sitectl-drupal",
"libops/sitectl-isle",
"libops/sitectl-libops"
]
no
org_id Google Cloud organization ID. string n/a yes
package_domain Fully qualified domain name that will serve the package repository. string "packages.libops.io" no
project_id Google Cloud project ID. string "libops-linux-packages" no
project_name Google Cloud project display name. string "libops-linux-packages" no
region Default Google Cloud region. string "us-east5" no

Outputs

Name Description
aptly_gpg_passphrase_secret_id Secret Manager secret ID for the Aptly key passphrase.
aptly_gpg_private_key_secret_id Secret Manager secret ID for the armored Aptly private key.
bucket_name Package bucket name.
dns_name_servers Name servers assigned to the managed zone. Delegate the zone at your registrar or parent DNS.
github_service_account_email Service account email used by GitHub Actions.
package_url Public HTTPS package repository URL.
project_id Google Cloud project ID.
workload_identity_provider Full Workload Identity Provider resource name for GitHub Actions auth.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors