# Terraform Provider for Threshold A community fork of [hashicorp/terraform-provider-boundary](https://github.com/hashicorp/terraform-provider-boundary) for [Threshold](https://repo.anhonesthost.net/CyberCoveLLC/threshold), itself a community fork of Boundary CE. ## About this fork - **Upstream:** `hashicorp/terraform-provider-boundary`, licensed MPL-2.0 (see [LICENSE](LICENSE) and [NOTICE](NOTICE)). This fork is not affiliated with, endorsed by, or supported by HashiCorp or IBM. - **What changed:** the Go module is `repo.anhonesthost.net/CyberCoveLLC/terraform-provider-threshold`, it builds against the Threshold `api` and `sdk` Go modules (`repo.anhonesthost.net/CyberCoveLLC/threshold/api` and `.../sdk`), and product wording in docs and schema descriptions says "Threshold". Release plumbing for HashiCorp's CRT/registry pipeline was removed. - **Compatibility:** resource and data source type names (`boundary_*`), provider arguments (`addr`, `auth_method_id`, ...) and the `BOUNDARY_*` environment variables are unchanged, so existing Terraform configurations keep working. Because the resource types start with `boundary_`, Terraform infers the provider local name `boundary`; keep `boundary = { source = ... }` in `required_providers`. - **Distribution:** there is no public registry for this provider. Install it from a release zip or a local build as described below. Its address is `repo.anhonesthost.net/cybercovellc/threshold`. ## Requirements - [Terraform](https://www.terraform.io/downloads.html) >= 0.13.x (or OpenTofu) - [Go](https://golang.org/doc/install) >= 1.26 (see `go.mod`), with `GOPRIVATE=repo.anhonesthost.net` if the Threshold modules are not publicly fetchable ## Installing Provider address: `repo.anhonesthost.net/cybercovellc/threshold`. Version `0.1.0` is used in the examples. ### 1. Build locally ```sh export GOPRIVATE=repo.anhonesthost.net make build-all VERSION=0.1.0 # or: scripts/build-release.sh 0.1.0 dist # single platform, no zip: go build -o terraform-provider-threshold . # with goreleaser installed: goreleaser build --snapshot --clean --single-target ``` `make build-all` writes `dist/terraform-provider-threshold___.zip` for linux, darwin and windows on amd64 and arm64 (needs `zip`). Never commit `dist/`. ### 2. Filesystem mirror (recommended for shared hosts) Terraform's `provider_installation` can serve providers from a local directory. Layout (unpacked form): ``` /usr/share/terraform/providers/ repo.anhonesthost.net/cybercovellc/threshold/0.1.0/linux_amd64/terraform-provider-threshold_v0.1.0 ``` or the packed form: `.../repo.anhonesthost.net/cybercovellc/threshold/terraform-provider-threshold_0.1.0_linux_amd64.zip`. Then in `~/.terraformrc` (`%APPDATA%\terraform.rc` on Windows): ```hcl provider_installation { filesystem_mirror { path = "/usr/share/terraform/providers" include = ["repo.anhonesthost.net/cybercovellc/threshold"] } direct { exclude = ["repo.anhonesthost.net/cybercovellc/threshold"] } } ``` and in your configuration: ```hcl terraform { required_providers { boundary = { source = "repo.anhonesthost.net/cybercovellc/threshold" version = "0.1.0" } } } provider "boundary" { addr = "https://threshold.example.com:9200" # auth_method_id / auth_method_login_name / auth_method_password, token, or recovery_kms_hcl } ``` ### 3. dev_overrides (development) Build the binary into a directory and point Terraform at it (`terraform init` is not needed, and `terraform plan` prints a warning): ```hcl # ~/.terraformrc provider_installation { dev_overrides { "repo.anhonesthost.net/cybercovellc/threshold" = "/home/you/go/bin" # directory holding terraform-provider-threshold } direct {} } ``` `go install .` places `terraform-provider-threshold` in `$GOPATH/bin`. `make dev` installs a `0.0.1` build into Terraform's implied local mirror under the same address. ## Building The Provider 1. Clone the repository 1. Enter the repository directory 1. Build with `go build -o terraform-provider-threshold .` (or `make dev`, which also builds the optional built-in KMS plugins from `plugins/kms/mains`) ## Adding Dependencies This provider uses [Go modules](https://github.com/golang/go/wiki/Modules). Please see the Go documentation for the most up to date information about using Go modules. To add a new dependency `github.com/author/dependency` to your Terraform provider: ```shell go get github.com/author/dependency go mod tidy ``` Then commit the changes to `go.mod` and `go.sum`. ## Developing the Provider If you wish to work on the provider, you'll first need [Go](http://www.golang.org) installed on your machine (see [Requirements](#requirements) above). To compile the provider, run `go install`. This will build the provider and put the provider binary in the `$GOPATH/bin` directory. Unit tests (no controller needed) run with `make test`. All other tests are acceptance tests and require a running Threshold/Boundary-compatible controller (`BOUNDARY_ADDR`, `BOUNDARY_AUTH_TOKEN`, `BOUNDARY_DEV_RECOVERY_KEY`) and, for the Vault tests, Docker. In order to run the full suite of Acceptance tests, a postgres docker container must be started first: ```sh $ go mod download # ensure boundary is installed, files are used by the docker image $ make test-database-up ``` Once the test database is ready the tests can be run using `make testacc`. *Note:* Acceptance tests create real resources, and often cost money to run. ```sh $ make testacc ``` For more details on the docker image and troubleshooting see the [Threshold contributing guide](https://repo.anhonesthost.net/CyberCoveLLC/threshold). ## Debugging the provider If you're using vscode, this provider has delve debugging baked into the [.vscode](https://repo.anhonesthost.net/CyberCoveLLC/terraform-provider-threshold/tree/main/.vscode) directory. To debug you can find instructions [here.](https://dev.to/drewmullen/vscode-terraform-provider-development-setup-debugging-6bn#usage) ## Generating Docs This provider uses the [terraform-plugin-docs](https://github.com/hashicorp/terraform-plugin-docs/) tool to generate documentation. Each resource and data source requires a set of examples [examples](https://repo.anhonesthost.net/CyberCoveLLC/terraform-provider-threshold/tree/main/examples) then you execute a binary to generate the docs which are placed in [./docs](https://repo.anhonesthost.net/CyberCoveLLC/terraform-provider-threshold/tree/main/docs). Optionally, you can specify your own [templates](https://repo.anhonesthost.net/CyberCoveLLC/terraform-provider-threshold/tree/main/templates) for a resource or data source if you want to add custom information (example: [data "boundary_scope"](https://repo.anhonesthost.net/CyberCoveLLC/terraform-provider-threshold/blob/main/templates/data-sources/scope.md.tmpl#L11)) ### New Resources & Data Sources (documentation templates) If you're adding a new resource or a data source, you must include a documentation template for your new R/DS in [./templates](https://repo.anhonesthost.net/CyberCoveLLC/terraform-provider-threshold/tree/main/templates) directory. This provider uses the [terraform-plugin-docs](https://github.com/hashicorp/terraform-plugin-docs/) tool to generate documentation. For full details see the link. ### Documentation Examples for Resources & Data Sources Examples are required for all resources and data sources. This provider uses the [terraform-plugin-docs](https://github.com/hashicorp/terraform-plugin-docs/) tool to generate documentation. To add examples, add a new file to the [./examples](https://repo.anhonesthost.net/CyberCoveLLC/terraform-provider-threshold/tree/main/examples) directory or update the existing files. Next make sure the corresponding template in [./templates](https://repo.anhonesthost.net/CyberCoveLLC/terraform-provider-threshold/tree/main/templates) directory references this example. ### Generating From the root of the repo run: ```shell go run github.com/hashicorp/terraform-plugin-docs/cmd/tfplugindocs ``` ## Using the provider Please see our detailed docs for individual resource usage. Below is a complex example using the provider to configure all resource types available: ```hcl provider "boundary" { addr = "http://127.0.0.1:9200" auth_method_id = "ampw_1234567890" # changeme auth_method_login_name = "myuser" # changeme auth_method_password = "passpass" # changeme } variable "users" { type = set(string) default = [ "Jim", "Mike", "Todd", "Jeff", "Randy", "Susmitha" ] } variable "readonly_users" { type = set(string) default = [ "Jeff", "Pete", "JT" ] } variable "backend_server_ips" { type = set(string) default = [ "10.1.0.1", "10.1.0.2", ] } resource "boundary_scope" "global" { global_scope = true scope_id = "global" } resource "boundary_scope" "corp" { scope_id = boundary_scope.global.id auto_create_admin_role = true auto_create_default_role = true } resource "boundary_user" "users" { for_each = var.users name = each.key description = "User resource for ${each.key}" scope_id = boundary_scope.corp.id } // organization level group for readonly users resource "boundary_group" "readonly" { name = "readonly" description = "Organization group for readonly users" member_ids = [for user in boundary_user.readonly_users : user.id] scope_id = boundary_scope.corp.id } // add org-level role for readonly access resource "boundary_role" "organization_readonly" { name = "readonly" description = "Read-only role" principal_ids = [boundary_group.readonly_users.id] grant_strings = ["ids=*;type=*;actions=read"] scope_id = boundary_scope.corp.id } // add org-level role for administration access resource "boundary_role" "organization_admin" { name = "admin" description = "Administrator role" principal_ids = concat( [for user in boundary_user.user: user.id] ) grant_strings = ["ids=*;type=*;actions=create,read,update,delete"] scope_id = boundary_scope.corp.id } // create a project for core infrastructure resource "boundary_scope" "core_infra" { description = "Core infrastrcture" scope_id = boundary_scope.corp.id auto_create_admin_role = true } resource "boundary_host_catalog" "backend_servers" { name = "backend_servers" description = "Backend servers host catalog" type = "static" scope_id = boundary_scope.core_infra.id } resource "boundary_host" "backend_servers" { for_each = var.backend_server_ips type = "static" name = "backend_server_service_${each.value}" description = "Backend server host" address = "${each.key}" host_catalog_id = boundary_host_catalog.backend_servers.id } resource "boundary_host_set" "backend_servers_ssh" { type = "static" name = "backend_servers_ssh" description = "Host set for backend servers" host_catalog_id = boundary_host_catalog.backend_servers.id host_ids = [for host in boundary_host.backend_servers : host.id] } // create target for accessing backend servers on port :8000 resource "boundary_target" "backend_servers_service" { type = "tcp" name = "backend_servers_service" description = "Backend service target" scope_id = boundary_scope.core_infra.id default_port = "8080" host_set_ids = [ boundary_host_set.backend_servers.id ] } // create target for accessing backend servers on port :22 resource "boundary_target" "backend_servers_ssh" { type = "tcp" name = "backend_servers_ssh" description = "Backend SSH target" scope_id = boundary_scope.core_infra.id default_port = "22" host_set_ids = [ boundary_host_set.backend_servers_ssh.id ] } ```