Naar de hoofdinhoud

De fremforge-provider voor Terraform en OpenTofu

De fremforge-provider beheert de fremforge-instellingen van je organisatie vanuit OpenTofu of HashiCorp Terraform: authenticatie- en toegangsbeleid, de IP-allowlist, scan- en scannerbeleid, onveranderlijke releases, handtekeningregels voor images en pakketten, de dependency-proxy, pakkettoegang en registerrobots.

Repository’s, teams en regels voor branchbeveiliging zijn Forgejo-objecten en blijven bij de community-provider svalabs/forgejo, zoals beschreven in Configuratie als code. De twee providers werken naast elkaar in één configuratie.

Installeren

De provider wordt op frem.sh zelf gepubliceerd, dus beide CLI’s installeren hem zonder extra configuratie:

terraform {
  required_providers {
    fremforge = {
      source  = "frem.sh/fremforge/fremforge"
      version = "~> 0.1"
    }
  }
}

tofu init (of terraform init) vindt het register via https://frem.sh/.well-known/terraform.json, downloadt de zip voor je platform van cli.frem.sh en controleert die tegen SHA256SUMS, waarvan het de OpenPGP-handtekening verifieert met de releasesleutel van fremforge. Er zijn builds voor Linux en macOS (amd64, arm64) en Windows (amd64).

De releasesleutel:

VingerafdrukAEA6 FE24 2C86 33F0 10C6 D4ED 9099 FD4F C1DC 23C4
Sleutel-ID9099FD4FC1DC23C4
Publiek certificaathttps://frem.sh/_app/terraform/signing-key.asc

De private sleutel verlaat het fremforge-platform nooit: elke release wordt door het platform ondertekend, en alleen voor de releasebuild van de provider.

Configureren

provider "fremforge" {
  # endpoint = "https://frem.sh/_app/api/v1"   # the default
}

De provider leest zijn token uit FREMFORGE_TOKEN. Gebruik een API-token van de organisatie die je beheert, aangemaakt onder Organisatiebeheer → API-tokens (frem.sh/<org>/_admin/api-tokens), met de scopes die je resources nodig hebben. Houd een token met alleen leestoegang voor plan en de schrijfscope voor de job die apply uitvoert:

ResourcesScope
Elke resource op deze paginapolicy:write
Alleen data sourcespolicy:read
fremforge_push_protection (lezen)findings:read

Resources

Instellingen van de organisatie zijn singletons: elke organisatie heeft ze altijd en de API kent geen delete. Elk argument is optioneel. Alleen de argumenten die je instelt, worden geschreven; de rest wordt teruggelezen in de state en met rust gelaten, dus een wijziging die iemand in de console aanbrengt aan een instelling die jij niet beheert, is geen drift. Importeer een singleton op de slug van de organisatie.

ResourceWat hij beheert
fremforge_auth_policyAuthenticatiebeleid: maximale levensduur van PAT’s (0 = geen maximum), PAT-scopes, ondertekende commits, keyless ondertekenaars, SSH aan of uit.
fremforge_ip_allowlistDe IP-allowlist van de organisatie. Een afdwingende lijst die het adres waar de CLI vandaan draait niet bevat, wordt door de API geweigerd; rol een lijst eerst uit met audit_only = true.
fremforge_operator_accessOf operators van fremforge de gebruikers van de organisatie mogen beheren.
fremforge_email_domain_policyOf de allowlist voor e-maildomeinen wordt afgedwongen.
fremforge_ssh_caDe SSH-certificaatautoriteit. require_cert = true vereist een CA-sleutel in dezelfde configuratie.
fremforge_actions_policyActions alleen op beveiligde branches.
fremforge_artifact_retentionBewaartermijn van Actions-artefacten in dagen.
fremforge_sla_policyHersteltermijnen per ernst (0 = geen).
fremforge_push_protectionWat een push doet als de secretscanner niet kan draaien.
fremforge_immutabilityOnveranderlijke releases en containertags. De plan waarschuwt wanneer releases aangaat: dat is niet terug te draaien voor de releases die worden gepubliceerd terwijl het aan staat.
fremforge_branch_protection_defaultsDe standaardinstellingen die fremforge op nieuwe repository’s toepast (geen Forgejo-regel).
fremforge_sast_settings, fremforge_dependency_scan_settings, fremforge_image_scan_settings, fremforge_secret_scan_settings, fremforge_license_settingsScannerinstellingen, één resource per scanner.
fremforge_image_signature_policyWelke imagehandtekeningen bij een pull worden vertrouwd, en of een pull zonder handtekening wordt geweigerd. Rol uit met mode = "shadow".
fremforge_dependency_proxyDe instellingen van de dependency-proxy van de organisatie.
fremforge_package_signature_policyDe handtekeningregel van het pakketbeleid (vereiste en vertrouwde ondertekenaars).
fremforge_package_access_defaultDe standaardmodus voor pakkettoegang van de organisatie.

Elke singleton is ook een data source met dezelfde naam.

Collecties hebben een echte create en delete:

ResourceImport-ID
fremforge_email_domain<org>/<pattern> of <org>/<id>
fremforge_scan_policy (één per scanner; iac_scan vanaf 0.4.0)<org>/<scanner>
fremforge_package_access<org>/<type>/<name>
fremforge_package_access_team_grant<org>/<type>/<team>/<name>
fremforge_package_access_actions_grant<org>/<type>/<repository>/<name>
fremforge_package_protection_rule<org>/<rule id>
fremforge_registry_robot<org>/<robot id>
fremforge_secret_custom_pattern (vanaf 0.3.0; repository vanaf 0.7.0)<org>/<pattern id>
fremforge_iac_custom_check (vanaf 0.4.0)<org>/<check id>
fremforge_ci_secret (vanaf 0.9.0)<org>/<NAME> / <org>/<repository id>/<NAME>

Een pakketnaam kan / bevatten (een npm-scope, een containerpad); daarom staat hij als laatste in de import-ID’s.

Voorbeeld

resource "fremforge_auth_policy" "this" {
  org                   = "acme"
  max_pat_lifetime_days = 30
  allow_user_pats       = false
  ssh_disabled          = true
}

resource "fremforge_ssh_ca" "this" {
  org          = "acme"
  ca_keys      = [file("ssh-ca.pub")]
  require_cert = true
}

resource "fremforge_scan_policy" "images" {
  org            = "acme"
  scanner        = "image_scan"
  mode           = "enforce"
  block_severity = "high"
}

Verwijderde instellingen

Op 2026-10-14 zijn twee instellingen uit fremforge verwijderd, omdat ze wel werden opgeslagen maar nooit toegepast: principal_policy op fremforge_ssh_ca en default_template_repo op fremforge_branch_protection_defaults. Sinds provider 0.1.1 zijn beide attributen deprecated: de provider verstuurt en leest ze niet meer, dus een configuratie die ze nog instelt, blijft werken en geeft een schoon plan, en tofu plan toont een deprecation-waarschuwing. Haal ze uit je configuratie; er verandert niets als je dat doet. Zie Branchbeveiliging en SSH-certificaatautoriteit.

Met provider 0.1.0 mislukt een fremforge_ssh_ca-blok waarvan principal_policy het enige argument is met HTTP 400 (no-fields), en wordt een niet-lege default_template_repo geweigerd met removed-setting. Upgrade met tofu init -upgrade (of terraform init -upgrade); version = "~> 0.1" pakt 0.1.1 op.

Scoped CI-secrets: de waarde komt nooit in de state

fremforge_ci_secret (vanaf provider 0.9.0) beheert één scoped CI-secret. De waarde is een write-only-argument, value_wo: die wordt verstuurd wanneer het secret wordt aangemaakt en bij elke wijziging (de API vervangt waarde en scope samen), en wordt nooit teruggelezen of opgeslagen in plan of state. Write-only-argumenten vereisen OpenTofu 1.11 of Terraform 1.11 of nieuwer. Laat repository_id weg voor de hele organisatie; verhoog value_wo_version om een nieuwe waarde te schrijven.

variable "deploy_key" {
  type      = string
  sensitive = true
  ephemeral = true
}

resource "fremforge_ci_secret" "deploy" {
  org              = "acme"
  name             = "DEPLOY_KEY"
  repository_id    = 42
  value_wo         = var.deploy_key
  value_wo_version = 1
  workflows        = ["deploy.yaml"]
  refs             = ["refs/heads/main"]
  events           = ["push", "workflow_dispatch"]
  environment      = "production"
}
  • Rotatie: fremforge kan de waarde niet tonen, dus een nieuwe value_wo alleen is geen wijziging. Verhoog value_wo_version om hem te schrijven.
  • Drift: een wijziging van scope of beschrijving buiten je configuratie verschijnt in het plan; een wijziging van de waarde niet.
  • Aanmaken neemt nooit over: bestaat er al een secret met die naam en die repository, dan faalt de apply en vraagt die je het te importeren.
  • Import: <org>/<NAME> voor een secret voor de hele organisatie, <org>/<repository id>/<NAME> voor een secret dat aan een repository is gebonden. Zet value_wo in de configuratie vóór de volgende apply.
  • Token-scopes: het token van de provider heeft ci-secrets:read en ci-secrets:write nodig.

De scope-argumenten worden vóór elk verzoek geweigerd wanneer ze de levering zouden kunnen verruimen: een lege regel, een gereserveerde naam (FORGEJO_, GITHUB_, GITEA_) of een repository-id dat geen positief getal is.

Tokens van registerrobots komen nooit in de state

De API toont het token van een registerrobot één keer, bij het uitgeven. De provider slaat het nooit op in de state, in geen enkel attribuut. Hij schrijft het token één keer, wanneer de API het uitgeeft (bij create, en telkens als je rotation wijzigt), naar het bestand dat je in token_file opgeeft, met modus 0600, en overschrijft nooit een bestaand bestand:

resource "fremforge_registry_robot" "ci" {
  org        = "acme"
  name       = "ci-pull"
  access     = "read"
  token_file = "${path.module}/.robot-ci.token"
  rotation   = "2026-10"   # change to issue a new token; the old one is revoked at once
}

Zonder token_file wordt het token weggegooid. Verplaats het bestand voordat je opnieuw roteert.

Drift, import en destroy

  • Drift: plan -detailed-exitcode eindigt met code 2 als een instelling die je beheert buiten je configuratie om is gewijzigd; apply zet haar terug.
  • Import: import { to = fremforge_auth_policy.this; id = "acme" }, waarna tofu plan -generate-config-out=generated.tf de configuratie voor je schrijft.
  • Destroy: bij een singleton haalt destroy hem alleen uit de state en verandert niets in de organisatie: standaardwaarden schrijven zou een beveiligingsinstelling stilletjes verzwakken. Collecties worden verwijderd. fremforge_package_access verwijdert de instellingen van het pakket en elke toekenning erop.

Overstappen vanaf de module

De module blijft gedocumenteerd zolang je overstapt. Voeg per instelling de resource van de provider toe, importeer hem op de slug van de organisatie, controleer dat plan geen wijzigingen toont, haal dan het argument uit de module en verwijder de bijbehorende restful_resource met tofu state rm.

Hoe we hem testen

Bij elke wijziging draait elke resource en data source door de echte OpenTofu-CLI tegen een opgenomen fremforge-API: alleen de argumenten die je instelt, worden geschreven, onbeheerde wijzigingen worden genegeerd, drift in beheerde instellingen komt in het plan, import leest dezelfde state terug, en destroy gedraagt zich zoals hierboven beschreven.

De instellingen die veilig te wijzigen zijn op een gedeelde organisatie, draaien daarnaast elke nacht live tegen een testorganisatie: apply, een schoon plan, een wijziging via de API, een plan dat die wijziging toont, apply, import in een nieuwe state, een schoon plan, destroy, teruglezen, en de oorspronkelijke waarde hersteld. Dat zijn het authenticatiebeleid, de SSH-CA, het SLA-beleid en het metadatafilter van de dependency-proxy; pakkettoegang, beveiligingsregels en registerrobots zijn vóór de release op dezelfde manier live getest. De IP-allowlist en het handtekeningbeleid worden alleen tegen de opgenomen API getest, omdat het wijzigen ervan op een gedeelde organisatie andere tests zou verstoren.